第七十三课:Node.js Express — 中间件使用和开发
学习目标
在这一课中,我们将深入了解Express中间件的概念和用法。我们将学习以下内容:
- 中间件的概念和作用。
- Express内置中间件的使用。
- 第三方中间件的接入和作用,以
body-parser
和morgan
为例。 - 如何开发自定义中间件。
完成本课后,你应该能够理解和实现中间件在Express应用中的应用,以及如何编写自己的中间件来扩展应用功能。
学习内容
中间件概念
在Express中,中间件是一个函数,它可以访问请求对象(req),响应对象(res),和应用程序的请求/响应循环中的下一个中间件函数(next)。中间件的功能包括:
- 执行任何代码。
- 修改请求和响应对象。
- 结束请求/响应循环。
- 调用堆栈中的下一个中间件。
如果当前中间件没有结束请求/响应循环,则必须调用next()
方法将控制权传递给下一个中间件,否则请求将被挂起。
内置中间件
Express 4.x版本之后没有内置body-parser
等中间件,但提供了如下内置中间件:
express.static
:用来托管静态文件。express.json
:解析JSON格式的请求体。express.urlencoded
:解析URL编码的请求体。
代码示例:
const express = require('express');
const app = express();
// 托管静态文件
app.use(express.static('public'));
// 解析JSON格式的请求体
app.use(express.json());
// 解析URL编码的请求体
app.use(express.urlencoded({ extended: true }));
// 应用监听端口
app.listen(3000);
预计输出效果:
服务器将能够处理静态文件、JSON格式的请求体和URL编码的请求体。
第三方中间件
第三方中间件可以提供更多功能,比如日志记录、请求体解析等。
body-parser
:用于解析请求体,Express 4.16+ 已经不需要这个库,因为express.json
和express.urlencoded
已经包含了这个库的功能。morgan
:HTTP请求日志中间件。
代码示例:
安装morgan
:
npm install morgan
使用morgan
:
const express = require('express');
const morgan = require('morgan');
const app = express();
// 使用morgan中间件
app.use(morgan('dev'));
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 应用监听端口
app.listen(3000);
预计输出效果:
每次有HTTP请求到服务器时,morgan
会在终端打印出有关请求的日志信息。
自定义中间件
开发自定义中间件可以让你执行特定的逻辑,比如检查用户权限、记录日志等。
代码示例:
const express = require('express');
const app = express();
// 自定义中间件
function logMethod(req, res, next) {
console.log('Request Type:', req.method);
next();
}
app.use(logMethod);
app.get('/', (req, res) => {
res.send('Hello World!');
});
// 应用监听端口
app.listen(3000);
预计输出效果:
每次收到请求时,都会在控制台输出请求的HTTP方法类型。
课后练习
- 创建一个Express服务器,并使用
express.static
中间件来托管一个包含图片、CSS文件和JavaScript文件的目录。 - 使用
morgan
中间件记录日志,并尝试自定义日志格式。 - 编写一个自定义中间件,用于验证请求中是否包含特定的HTTP头(比如
x-api-key
),如果没有则返回状态码403。 - 将一个自定义中间件应用到一个特定的路由上,而非全局。
练习解析
对于上述练习,以下是一个解析示例:
对于第3个练习,你的自定义中间件可能如下所示:
function checkApiKey(req, res, next) {
const apiKey = req.get('x-api-key');
if (!apiKey || apiKey !== 'expected-api-key') {
res.status(403).send('Access Denied');
} else {
next();
}
}
app.use(checkApiKey);
app.get('/api/data', (req, res) => {
res.json({ data: 'Some protected data' });
});
当你尝试访问/api/data
路由而没有提供正确的x-api-key
头时,你应该会收到一个状态码为403的响应,说明你无权访问该资源。
对于第4个练习,你可以这样只对一个特定的路由使用中间件:
app.get('/api/data', checkApiKey, (req, res) => {
res.json({ data: 'Some protected data' });
});
这样,只有/api/data
路由会要求进行API密钥检查。其他路由则不会受到此中间件的影响。