日志中间件
// 挂载会每个接口都执行这段代码
app.use((req,res,next)=>{
console.log(req.method,req.url,Date.now())
next() //下一个中间件
})
2.中间件的顺序很重要
如果有一个普通接口写在上面代码之前,那么就不会进入上面的函数中
但是如果在接口中第二个回调函数的参数中加入next,则可以进入
// 不会打印时间戳及相关信息
app.get("/todos", async (req, res) => {
try {
const db = await getDB();
res.status(200).json(db.todos);
} catch (err) {
return res.status(500).json({ error: err.message });
}
});
// 可以打印了~
app.get("/todos", async (req, res, next) => {
try {
const db = await getDB();
res.status(200).json(db.todos);
next()
} catch (err) {
return res.status(500).json({ error: err.message });
}
});
我是讲武德的,这些课件截图源于b站up主小打小闹Studio
https://space.bilibili.com/13625996
在中间件函数中可以执行以下任何任务:
1).执行任何代码
2).修改request或response响应对象
3).结束请求响应周期
4).调用下一个中间件
如果当前的中间件功能没有结束请求-响应周期,则必须使用next()将控制权传递给下一个中间件功能。否则,该请求将被挂起。
2.Express中间件分类:
1)应用程序级别中间件 express实例.xxx
2)路由级别中间件 express.Router()
3)错误处理中间件 和其他中间件函数一样,但是四个参数
4)内置中间件
5)第三方中间件
1)通过Express实例挂载的中间件
a)不做任何限定的中间件
app.use((req, res, next) => {
console.log(req.method, req.url, Date.now());
next(); //下一个中间件
});
b)限定请求方法+请求路径的中间件
就是符合条件的APi被调用后才会进入这个中间件
//限定请求路径
app.use('/task',(req, res, next) => {
console.log(req.method, req.url, Date.now());
next(); //下一个中间件
});
app.get('/task',(req, res, next) => {
res.status(200).send('是否会进入?')
})
//----页面进入/task中间件去打印方法和时间戳也会有‘是否进入’
//限定请求路径
app.use('/aaa',(req, res, next) => {
console.log(req.method, req.url, Date.now());
next(); //下一个中间件
});
//---这种就是不会进入打印了,因为匹配不上了
c)多个处理函数
app.use(
"/",
(req, res, next) => {
console.log(req.method, req.url, Date.now());
next();
},
(req, res, next) => {
console.log('也会进来吗');
// next(); //如果注释掉就不会进入下面的接口了
}
);
app.get("/", (req, res, next) => {
res.status(200).send("是否会进入?");
});
d)next('route') 下一步进入请求,而不是普通下一步
app.get(
"/user/:id",
function (req, res, next) {
console.log(req.method, req.url, Date.now());
console.log(typeof(req.params.id),'999')
if (req.params.id === '2') {
next("route"); //跳过也会进来吗函数的执行,直接进入是否会进入
} else {
next(); //继续往下执行
}
},
function (req, res, next) {
console.log("也会进来吗");
next();
}
);
app.get("/user/:id", (req, res, next) => {
res.status(200).send("是否会进入?");
});
2)路由级别中间件
每个请求都需要app.xxx太过于繁琐 ,可以使用路由实例 相当于mini express 实例
后续就通过router.xxx()
a)根目录下创建一个router.js 文件,创建一个router实例
const express = require('express')
const router = express.Router()
b)配置路由
router.get('/',(req,res,next)=>{})
c) 导出路由实例
module.exports = router
d)将路由集成/挂载到Express实例应用中
const router = require('./router);
app.use(router)
//app.use('/abc',router) //在所有的路由前面都叫上限定访问的前缀
//可以将在app.js中写的所有路由配置放到router.js去
3)错误处理中间件
与其他中间件函数相同的方式定义错误处理中间件函数,除了使用四个参数而不是三个参数,一定是四个参数
一般在所有的中间件之后挂载错误处理函数中间件
app.use((err,req,res,next)=>{
console.log(err.stack)
res.status(500).json({error:err.message})
})
在try catch中的catch里面使用next(err),传递错误的信息,跳过所有剩余的非错误处理路由和中间件函数,其实就是报错之后去触发错误处理函数,然后就结束任务
在router.js中将前面的所有路由中间件的catch里面都修改成next(err)
router.post("/todos", async (req, res,next) => {
try {
const db = await getDB();
const reqBd = req.body;
if (!reqBd.title) {
return res.status(422).send({ error: "The field title is required" });
}
const lastTodoItem = db.todos[db.todos.length - 1];
db.todos.push({
id: lastTodoItem ? lastTodoItem.id + 1 : 1,
title: reqBd.title,
});
await saveDB(db);
res.status(200).send("添加成功!");
} catch (err) {
next(err);
}
});
模拟一下报错的场景,正常可以响应500与对应的错误信息
通常我们会在最后的位置放置一个404的处理中间件函数,其实出现404的时候也有一个默认的html提示样式界面
404 与500类型的中间件没有先后的影响,会对应触发,但是其余会依此从上往下执行
app.use((req,res,next)=>{
res.status(404).send('404 not found)
})
4)内置中间件
express.json() ---application/json
express.urlencoded() ---application/x-www-form-urlcoded
express.raw() ---application/octet-stream
express.text() ---text/plain
express.static() ---托管静态资源文件
5)第三方中间件
为了极简灵活的特性,epxress4之后将很多的中间件进行独立 ----middleware module
看文档使用即可
https://expressjs.com/zh-cn/resources/middleware.html
demo使用这些第三方中间件~~ 日志输出中间件
a)装包 npm install morgan
b)引入 var morgan = require('morgan')
c)挂载 app.use(morgan('tiny'))