Express(二) ——中间件
现在居住在深圳的社区被封了,整理下写的没发布的文章
个人博客:Express(二) ——中间件
Express(一) ——简单入门
在Express中,中间件是一个可以访问请求对象、响应对象和调用next方法的一个函数。
1. 简单例子(打印请求日志)
一个 Express 应用,就是由许许多多的中间件来完成的。
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}/`);
})
可以发现:任何请求进来都会先打印请求日志,然后才会执行具体的业务处理函数
2. 中间件的组成
app.use('/', (req, res, next) => { // 其中use可以是get、post等,用于限定请求路径
next(); // 这个例子就是所有请求路径为根路径的请求都会通过这个中间件
// 如果当前中间件没有结束请求相应周期,则需要通过next()调用下一个中间件,否则,该请求将会被挂起
})
如果当前中间件没有结束请求相应周期,则需要通过next()调用下一个中间件,否则,该请求将会被挂起
3. 中间件功能
- 执行任何代码
- 修改request或response对象
- 结束请求响应周期
- 调用下一个中间件
4. 中间件分类
4.1 应用程序级别中间件
4.1.1 不做任何限定的中间件
即所有请求都会通过该中间件
app.use(function (req, res, next) {
res.send('不做任何限定的中间件');
})
4.1.2 限定请求路径
即只有请求路径匹配才会通过该中间件
app.use('/user/:id', function (req, res, next) {
res.send('限定请求路径的中间件');
})
4.1.3 限定请求方法 + 请求路径
不能只限定请求方法,因为app.get()第一个参数必须
app.get('/', (req, res) => {
res.send('限定请求方法 + 请求路径的中间件');
})
4.1.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.1.5 多个路由处理函数
app.use('/', (req, res, next) => {
console.log('第一个路由处理函数');
next(); // 如果这里是res.end(),那么就会结束响应。第二个路由处理函数就没有机会执行
})
app.use('/', (req, res, next) => {
console.log('第二个路由处理函数');
res.end();
})
4.1.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。
4.2 路由级别中间件
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/');
})
链式路由处理程序:
app.route('/abc')
.get((req, res) => {
res.send('get');
})
.post((req, res) => {
res.send('post');
})
4.3 错误处理中间件
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对象
app.js
const express = require('express');
const app = express();
const router = require('./router.js');
app.use(router);
app.use((err, req, res, next) => { // 四个参数都要有才是错误处理中间件。如果只有err、req、res,则err实际上是req对象
console.log('错误: ', err);
res.status(500).json({
error: err.message
})
})
app.listen(3000, () => {
console.log('http://localhost:3000/');
})
router.js
const express = require('express');
// 1.创建路由实例
const router = express.Router();
// 2. 配置路由
router.get('/', (req, res, next) => {
try {
const d = b + 1;
} catch (err) {
next(err); // 跳过所有剩余的无错误处理路由和中间件函数
}
})
router.get('/', (req, res, next) => {
console.log('第二个路由处理函数');
res.end();
})
// 3. 导出路由实例
module.exports = router
// 4. 将路由挂载(集成)到Express实例应用中
4.4 内置中间件
- 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():托管静态资源文件
4.5 第三方中间件
使用示例:morgan日志中间件
-
npm install morgan
-
const express = require('express'); const morgan = require('morgan'); // 1. 引入 const app = express(); app.use(morgan('tiny')); // 2. 挂载 app.get('/', (req, res) => { res.send('Hello World!'); }) app.listen(3000, () => { console.log('http://localhost:3000/'); })
-
每次请求都会打印出请求日志