本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力。
中间件的字面意思是放在软件一层和另一层中间的任何东西。Express 中间件(Middleware)是在 Express 服务每个请求的生命周期内执行的函数。
体验 Express 中间件
我们简单体验一下中间件。首先,创建一个项目,进入目录执行
npm init
npm install express --save
创建一个 server.js ,其内容如下:
const express = require('express');
const app = express();
app.get('/', (req, res, next) => {
res.send('欢迎回家');
});
app.listen(3000);
通过 node server.js
启动服务,访问 http://localhost:3000
,您应该会在浏览器中看到“欢迎回家”。
(req, res, next) => {
res.send('欢迎回家');
}
以上示例中的这个匿名函数就是一个中间件 函数,它结束了请求,向客户端返回了 欢迎回家
字符串。
中间件的格式和用处
Express 中间件函数可以访问请求对象 (req
)、响应对象 (res
) 和下一个中间件函数。下一个中间件函数通常由名为 next
的变量表示。
function middware(req, res, next) => {
console.log(req);
next();
}
如果一个请求匹配了多个中间件函数,那么每个中间件将按顺序依次执行,直至请求结束。如下图所示。
当然在每个中间件过程中,也可以自己终止请求,这样下一个中间件函数就不会被执行到了。
中间件功能可以执行以下任务:
- 执行任何代码。
- 对请求和响应对象进行更改。
- 结束请求-响应循环。
- 调用堆栈中的下一个中间件。
如果当前中间件函数没有结束请求-响应循环,则必须调用 next()
将控制权传递给下一个中间件函数。 否则,请求将被挂起。
通过中间件,我们能更有序的组织代码。
中间件的分类
根据中间件的使用场景,大致可以分为以下几类中间件
- 应用级别中间件
app.use
- 路由级别中间件
router.use
- express 内置中间件
express.static,express.json,express.urlencoded
- 错误处理中间件
app.use(err,req,res,next)
- 第三方中间件
bodyparser,cookieparser
应用级别中间件
简单日志示例 log.js:
const express = require('express');
// custom middleware create
const LoggerMiddleware = (req,res,next) =>{
console.log(`Logged ${req.url} ${req.method} -- ${new Date()}`)
next();
}
const app = express()
// application level middleware
app.use(LoggerMiddleware);
// users route
app.get('/users',(req,res)=>{
res.json({
'status':true
})
})
app.listen(3002,(req,res)=>{
console.log('server running on port 3002')
})
启动服务 node log.js
, 访问 localhost:3002
localhost:3002/users
,可以看到如下日志:
server running on port 3002
Logged / GET -- Sat Aug 21 2021 11:54:28 GMT+0800 (GMT+08:00)
Logged /users GET -- Sat Aug 21 2021 11:56:18 GMT+0800 (GMT+08:00)
路由级别中间件
路由器级中间件的工作方式与应用级中间件相同,只是它绑定到 express.Router()
的实例。
const router = express.Router()
使用 router.use()
、及 router.post()
类似的函数加载路由器级中间件。
const express = require('express');
const app = express();
const router = express.Router()
router.use((req,res,next)=>{
console.log("Time:",new Date())
next()
})
router.get("/user/:id",(req,res,next)=>{
console.log('Request URL:', req.originalUrl)
next()
},(req,res,next)=>{
console.log('Request Type:', req.method)
next()
},(req,res)=>{
res.json({
status:true,
id:req.params.id
})
})
app.use('/',router)
app.listen(3000,(req,res)=>{
console.log('server running on 3000')
})
server running on 3000
Time: 2021-08-21T04:02:19.781Z
Request URL: /user/1
Request Type: GET
Time: 2021-08-21T04:02:24.002Z
Request URL: /user/123
Request Type: GET
内置中间件
Express 内置了以下中间件功能:
- express.static 提供静态资产,例如 HTML 文件、图像等。
- express.json 使用 JSON 负载解析传入请求。 注意:适用于 Express 4.16.0+
- express.urlencoded 使用 URL 编码的有效负载解析传入请求。 注意:适用于 Express 4.16.0+
示例:以下操作将 public 默认为静态资源目录,并做一些配置。
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now())
}
}
app.use(express.static('public', options))
错误处理中间件
Express JS 自带默认的错误处理参数,定义错误处理中间件函数的方式与其他中间件函数相同,只是错误处理函数有四个参数而不是三个:
app.get('/my-other-thing', (req, res, next) => {
next(new Error('I am passing you an error!'));
});
app.use(function (err, req, res, next) {
console.error(err.stack)
res.status(500).send('Something broke!')
})
第三方中间件
在某些情况下,我们会向后端添加一些额外的功能。安装特定的第三方中间件,然后在应用程序级别或路由器级别将其加载到您的应用程序中。譬如 bodyparser
,cookieparser
。示例:
var express = require('express')
var cookieParser = require('cookie-parser')
var app = express()
app.use(cookieParser())
app.get('/', function (req, res) {
// Cookies that have not been signed
console.log('Cookies: ', req.cookies)
// Cookies that have been signed
console.log('Signed Cookies: ', req.signedCookies)
})
app.listen(8080)
带 cookie 访问curl http://127.0.0.1:8080 --cookie "Cho=Kim;Greet=Hello"
,可以看到如下效果:
Cookies: { Cho: 'Kim', Greet: 'Hello' }
Signed Cookies: [Object: null prototype] {}
最后
通过以上的学习,希望对大家有所帮助。原创不易,感谢阅读,欢迎点赞收藏。
以下是笔者之前的文章,有兴趣可以继续阅读。