Express 使用中间件
概述
Express,作为一个轻量级的Web框架,其核心思想在于路由和中间件机制。简言之,一个Express应用其实就是一系列中间件函数的集合,它们共同协作来处理HTTP请求和响应。
如果当前的中间件函数没有通过调用next()
函数来结束其执行并传递控制权,那么请求将被“挂起”,不再继续向下处理。
Express 中间件类型
在Express中,中间件可以分为以下几类:
- 应用级中间件:这类中间件绑定到整个Express应用上,无论请求的路径是什么,它们都会被执行。
- 路由级中间件:与特定路由路径相关联的中间件,只有在请求的URL与路由路径匹配时才会被调用。
- 错误处理中间件:专门用于捕获和处理在请求处理过程中发生的错误。
- 内置中间件:Express自身提供的一些常用中间件,例如用于解析JSON数据或URL编码数据的中间件。
- 第三方中间件:由社区开发的中间件,它们为Express应用提供了更多的功能和扩展性。
如何加载中间件?
在Express应用中,你可以通过指定一个可选的挂载路径来加载应用级和路由级中间件。此外,你还可以将多个中间件函数组合在一起,形成一个中间件子堆栈,并在特定的挂载点加载它们。这种灵活的配置方式使得Express应用能够轻松实现各种复杂的请求处理逻辑。
应用级中间件的使用
在 Express 应用中,应用级中间件可以处理所有请求,无论它们的路径或HTTP方法如何。你可以通过 app.use()
和 app.METHOD()
方法将中间件绑定到应用对象的实例。其中 METHOD
是小写的 HTTP 方法名称,如 get
、post
、put
等。
示例:无路径挂载的中间件
以下示例中的中间件函数没有特定的挂载路径,因此它将在每次应用接收到请求时执行。
const express = require('express');
const app = express();
app.use((req, res, next) => {
console.log('Current Time:', Date.now());
next();
});
示例:带路径挂载的中间件
这个例子中的中间件函数被挂载在 /user/:id
路径上,它将对所有类型的 HTTP 请求进行处理。
app.use('/user/:id', (req, res, next) => {
console.log('Request Method:', req.method);
next();
});
示例:路由及处理函数
以下示例展示了如何为 /user/:id
路径上的 GET 请求定义一个路由处理函数。
app.get('/user/:id', (req, res, next) => {
res.send('USER');
});
中间件子堆栈
中间件子堆栈允许你为特定路径挂载多个中间件函数。下面的例子中,任何对 /user/:id
路径的 HTTP 请求都会打印出请求的原始 URL 和请求类型。
app.use('/user/:id', (req, res, next) => {
console.log('Request URL:', req.originalUrl);
next();
}, (req, res, next) => {
console.log('Request Method:', req.method);
next();
});
路由处理程序
你可以为同一路径定义多个路由处理程序。需要注意的是,一旦某个请求被响应,后续的路由处理程序将不会被调用。
app.get('/user/:id', (req, res, next) => {
console.log('User ID:', req.params.id);
next();
}, (req, res, next) => {
res.send('User Info');
});
// 这个路由处理程序实际上不会被调用,因为前一个已经结束了请求-响应周期。
app.get('/user/:id', (req, res, next) => {
res.send(req.params.id);
});
使用 next('route')
跳过中间件
要跳过当前路由的所有剩余中间件并传递控制权给下一个路由,可以使用 next('route')
。
app.get('/user/:id', (req, res, next) => {
if (req.params.id === '0') {
next('route'); // 跳过当前路由的剩余中间件
} else {
next(); // 继续执行当前中间件栈中的下一个中间件
}
}, (req, res, next) => {
res.send('regular');
});
// 另一个路由处理程序,当上一个中间件跳过时,这个处理程序会被调用
app.get('/user/:id', (req, res, next) => {
res.send('special');
});
中间件的数组声明
中间件还可以声明为数组,以提高代码的可重用性。通过这种方式,你可以轻松地将多个中间件逻辑组合在一起,以用于不同的路由。
function logOriginalUrl(req, res, next) {
console.log('Request URL:', req.originalUrl);
next();
}
function logMethod(req, res, next) {
console.log('Request Method:', req.method);
next();
}
const logStuff = [logOriginalUrl, logMethod];
app.get('/user/:id', logStuff, (req, res, next) => {
res.send('User Info');
});
路由级中间件
路由级中间件与应用级中间件的工作方式相似,但它是绑定到一个特定的路由实例上的。在Express框架中,路由级中间件通过express.Router()
创建,并使用router.use()
和router.METHOD()
方法来加载。
示例代码
以下是使用路由级中间件的示例代码,展示了如何在不同的路由上应用中间件。
const express = require('express');
const app = express();
const router = express.Router();
// 通用中间件,打印请求时间和URL
const logRequest = (req, res, next) => {
console.log('Time:', Date.now(), 'Request URL:', req.originalUrl);
next();
};
// 特定于/user/:id的中间件,打印请求类型
const logMethod = (req, res, next) => {
console.log('Request Type:', req.method);
next();
};
router.use(logRequest); // 应用通用中间件
router.use('/user/:id', logMethod); // 应用特定中间件
// 处理/user/:id路径的GET请求,如果用户ID为0,则跳过当前路由的其余中间件
router.get('/user/:id', (req, res, next) => {
if (req.params.id === '0') {
next('route');
} else {
// 渲染常规页面
res.render('regular');
}
});
// 另一个处理/user/:id路径的GET请求,渲染特殊页面
router.get('/user/:id', (req, res) => {
console.log(req.params.id);
res.render('special');
});
// 将router挂载到app上
app.use('/', router);
// 捕获所有未匹配的请求,并返回401状态码
app.use((req, res) => {
res.sendStatus(401);
});
错误处理中间件
在Node.js的Express框架中,错误处理中间件是一种特殊的中间件,用于处理请求-响应循环中的异常和错误。它通常用于捕获并处理应用中的未捕获错误,确保即使在出现错误的情况下,用户也能得到适当的响应。
错误处理中间件函数的签名与常规中间件不同,它需要四个参数:(err, req, res, next)
。这四个参数分别代表:
err
:错误对象,包含了错误信息和堆栈跟踪。req
:请求对象,包含了请求的相关信息。res
:响应对象,用于发送响应给客户端。next
:调用下一个中间件的函数(在错误处理中间件中通常不使用)。
定义错误处理中间件
定义错误处理中间件时,确保使用四个参数,并将其放置在所有其他中间件之后,确保它能够捕获到任何未被其他中间件处理的错误。
const express = require('express');
const app = express();
// 常规中间件
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
内置中间件
从Express 4.x版本开始,框架不再依赖于Connect中间件。之前内置在Express中的一些中间件功能现在被分离出来,形成了独立的模块。以下是Express框架提供的内置中间件函数:
- express.static:该中间件用于提供静态资源,包括HTML文件、图片、CSS文件等,方便地将这些资源服务给客户端。
- express.json:此中间件用于解析传入请求的JSON有效负载。从Express 4.16.0版本开始,该功能被内置到框架中。
- express.urlencoded:此中间件用于解析使用URL编码格式的请求负载。同样,从Express 4.16.0版本开始,该功能也被内置到框架中。
注意,虽然这些中间件在Express 4.16.0及以上版本中是内置的,但在早期版本中,它们可能需要单独安装和配置。在实际中,开发者应根据自己使用的Express版本来决定是否需要额外安装这些中间件。
第三方中间件
在Express应用中,第三方中间件可以提供额外的功能和扩展性。以下是如何安装和使用第三方中间件的步骤:
1、安装所需模块:首先,你需要通过npm(Node Package Manager)安装提供所需功能的Node.js模块。以cookie-parser
为例,这是一个解析HTTP请求中cookie的中间件。
$ npm install cookie-parser
2、加载中间件到应用:安装完成后,在你的Express应用代码中,需要先引入express
和cookie-parser
模块,然后通过调用app.use()
方法将cookie-parser
中间件加载到应用中。
const express = require('express');
const app = express();
const cookieParser = require('cookie-parser');
// 加载cookie解析中间件
app.use(cookieParser());
Express常用的第三方中间件列表
以下是一些常用的第三方中间件的示例,完整的列表请参考 第三方中间件:
- cookie-parser:解析HTTP请求中的cookie。
- morgan:HTTP请求的日志记录器。
- body-parser:解析多种格式的请求体,包括JSON、URL编码的表单数据等。
- cors:提供跨源资源共享(CORS)支持。
- helmet:帮助保护应用免受某些类型的Web攻击。
- express-session:为Express添加会话支持。
注意,第三方中间件的可用性和功能可能会随着时间的推移而变化,在选择和使用时,应查阅最新的文档或社区反馈。