以.use的都是中间件,顾名思义中间执行的比如
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log(`请求日志:${req.method} ${req.url} ${new Date()}`);
next(); // 放行
})
app.get('/', (req, res) => {
res.send('get / ');
})
app.post('/', (req, res) => {
res.send('post / ');
})
app.delete('/', (req, res) => {
res.send('delete /')
})
const port = 3000;
app.listen(port, () => {
console.log(`http://localhost:${port}/`);
})
可以发现无论任何请求都要先打印app.use里面的'请求日志'
2.怎么组成中间件
app.use('/', (req, res, next) => { // 其中use可以是get、post等,用于限定请求路径
next(); // 这个例子就是所有请求路径为根路径的请求都会通过这个中间件
// 如果当前中间件没有结束请求相应周期,则需要通过next()调用下一个中间件,否则,该请求将会被挂起
})
3.中间件能做什么
- 执行任何代码
- 获取req和res,并修改它们
- 结束请求,或者调用下一个中间件
4.不同的中间件示例
4.1 没有任何修改,限制的中间件
所有请求都会通过它
app.use(function (req, res, next) {
res.send('不做任何限定的中间件');
})
4.2 有请求路径
只有请求路径匹配才会通过它
app.use('/user/:id', function (req, res, next) {
res.send('限定请求路径的中间件');
})
4.3 有请求方法+请求路径
当然这也是一个中间件
app.get('/', (req, res) => {
res.send('限定请求方法 + 请求路径的中间件');
})
4.4 多次处理
app.use(function (req, res, next) {
console.log('第一次处理');
next(); // 这个next()之后就是第二个处理函数
}, function (req, res, next) {
console.log('第二次处理');
next(); // 这个next()之后则是脱离当前处理栈,往后寻找匹配调用
})
或者调用回调函数数组
const first = (req, res, next) => {
console.log('第一次处理');
next();
};
const second = (req, res, next) => {
console.log('第二次处理');
next();
};
app.use([first, second]);
4.5 多个路由处理函数
app.use('/', (req, res, next) => {
console.log('第一个路由处理函数');
next(); // 如果这里是res.end(),那么就会结束响应。第二个路由处理函数就没有机会执行
})
app.use('/', (req, res, next) => {
console.log('第二个路由处理函数');
res.end();
})
4.6中间件子堆栈
app.get('/:id', function (req, res, next) {
if (req.params.id === '0') {
next('route'); // 跳过当前堆栈之后的所有中间件。即不执行后面的处理函数,而是直接去执行后面的路由处理函数
// (处理函数和路由处理函数看上面的例子)
} else {
next();
}
}, function (req, res, next) {
res.send('regular');
})
app.get('/:id', function (req, res, next) {
res.send('special');
})
上面例子中,动态参数id不为0时,第一个处理函数会调用next(),然后会执行第二个处理函数,然后会收到regular的响应。而当id为0时,会调用next(‘route’),会跳过当前堆栈之后的所有中间件。即不执行后面的处理函数,而是直接去执行后面的路由处理函数。所以不会打印regular,而是打印special。
5.路由中间件
单独封装出router.js
const express = require('express');
// 1.创建路由实例
const router = express.Router();
// 2. 配置路由
router.get('/aaa', (req, res) => {
res.send('get /aaa');
})
router.post('/bbb', (req, res) => {
res.send('post /bbb');
})
// 3. 导出路由实例
module.exports = router
// 4. 将路由挂载(集成)到Express实例应用中(见app.js)
然后在app.js去导入
const express = require('express');
const app = express();
const router = require('./router.js');
app.get('/', (req, res) => {
res.send('Hello World!');
})
// 4. 将路由挂载(集成)到Express实例应用中
app.use('/abc', router); // 给路由限定访问前缀/abc
app.listen(3000, () => {
console.log('http://localhost:3000/');
})
abc是这个路由的限制前缀,router.js里面定义的路由需要加上这个前缀,不然404
6.错误处理中间件
app.use((err, req, res, next) => { // 四个参数都要有才是错误处理中间件。如果只有err、req、res,则err实际上是req对象
console.log('错误: ', err);
res.status(500).json({
error: err.message
})
})
四个参数都要有才是错误处理中间件。如果只有err、req、res,则err实际上是req对象
7 内置中间件
express.json():解析Content-Type为application/json格式的请求体 express.urlencoded():解析Content-Type为application/x-www-form-urlencoded格式的请求体 express.raw():解析Content-Type为application/octet-stream格式的请求体 express.text():解析Content-Type为text/plain格式的请求体 express.static():托管静态资源文件
8第三方中间件
Express middleware