4.6 中间件
中间件是一个函数,在应用的请求-响应周期中,能够访问请求对象、响应对象和next函数。
中间件可以执行以下任务:
· 执行逻辑代码。
· 更改请求和响应对象。
· 结束请求-响应周期。
· 调用下一个中间件。
如果当前的中间件没有调用next(),也没有结束请求-响应周期,则该请求将被挂起。
中间件有路由中间件和全局中间件两种。全局中间件对任何请求都会生效,路由中间件只对特定的路由生效。
4.6.1 全局中间件
以下是全局的日志中间件示例,该中间件打印当前的请求方法、请求路径以及User-Agent。
访问http://localhost:8080,客户端会收到Hello World响应,并且在终端会输出以下日志:
GET / "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
GET /favicon.ico "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
访问http://localhost:8080/user,客户端会收到user响应,终端同样会输出请求日志。
4.6.2 路由中间件
还是以刚才的中间件为例,不过我们将其挂载到特定的路由上。
访问http://localhost:8080,终端会输出请求日志,但是访问http://localhost:8080/user时终端不会输出请求日志。
4.6.3 可配置的中间件
在请求对象这一节中,我们使用了如下代码来挂载中间件。
app.use(cookieParser());
在上面的内容中,我们使用的下面代码。
app.use(logger);
cookieParser()是函数调用,支持传入配置,并且返回一个中间件。cookieParser()的代码结构如下:
function cookieParser(options) { return function(req, resp, next) { }; }
我们针对日志中间件做一下修改来支持配置:
4.6.4 Cookie中间件
在前面的内容中我们使用cookie-parser来读取cookie,本节将和大家一起来编写一个cookie-parser。
通过请求报头可以获取原始的cookie请求报头:
可以看到每个cookie之间以分号分隔,cookie的名字和cookie值通过等号分隔,所以编写cookie的思路如下:
(1)读取请求报头的cookie字段。
(2)使用";"来分隔每个cookie。
(3)针对单个cookie,使用"="分隔名字和值。
(4)将获取到的cookie名字和值挂载到req.cookies对象上。
4.6.5 响应时长中间件
有些场景下需要统计请求开始到请求结束阶段,服务器处理请求所花费的时长,目前的中间件是无法获取到“请求结束”事件的。
Express的响应对象提供了“finish”事件来告知请求结束事件。我们基于该事件来编写响应时长中间件。
访问http://localhost:8080时,终端会打印响应时长。
监听resp事件需要使用once,使用on会引起内存泄露。
4.6.6 静态资源中间件
为了提供图片、CSS和JS之类的静态文件的访问,可以使用内置的express.static中间件。
express.static(root, [options])
· root:服务器文件夹路径。
· options:选项。
以下是一个提供静态资源访问的示例。
项目目录结构如下:
// 导入express模块 const express = require('express'); const app = express(); app.use(express.static('./public')); // 将静态资源中间件挂载到全局 // 开启监听 app.listen(8080, () => { console.log('listen on 8080'); });
上面的代码需要访问http://localhost:8080/css/style.css才能获取style.css。
也就是说public目录在请求链接中不能出现,如果需要将静态资源挂载到/public这个路由前缀下,可以使用下面的代码:
app.use('/public', express.static('./public'));
上面的代码需要访问http://localhost:8080/public/css/style.css才能获取style.css。