第七章:Node.js 实战入门指南 - Express 中间件和路由
在 第六章:Node.js 实战入门指南 - Express 框架入门我们简单的学习了Express的基础
在本章中,我们将学习 Express 框架中间件的概念和作用,以及如何使用内置中间件和自定义中间件来增强应用程序的功能。我们还会学习如何处理路由和路由参数,以实现灵活的路由控制。
1. 中间件的概念和作用
中间件是 Express 框架的核心概念之一。它允许我们在请求和响应的处理过程中执行一系列的操作。中间件函数可以访问请求对象(req
)、响应对象(res
)和下一个中间件函数(next
),并对它们进行处理或传递。
中间件的作用包括但不限于:
- 执行公共的前置操作,如身份验证、权限检查等。
- 处理请求和响应数据,如解析请求体、修改响应头等。
- 实现日志记录、错误处理、缓存等功能。
- 控制请求流程,如路由控制、错误处理流程等。
2. 使用内置中间件和自定义中间件
Express 提供了一些内置的中间件函数,可以直接在应用程序中使用。例如,express.json()
中间件用于解析 JSON 请求体,express.static()
中间件用于提供静态文件服务。
此外,我们还可以自定义中间件函数来满足应用程序的特定需求。自定义中间件可以在路由处理前或后执行,以实现一些自定义的操作,如日志记录等。
3. 实现常见的中间件功能
通过自定义中间件函数,我们可以实现各种常见的功能。例如,我们可以编写一个日志记录中间件来记录每个请求的详细信息,方便调试和监控。另外,我们还可以编写一个身份验证中间件来验证用户的身份并保护敏感路由。
这些中间件函数可以通过访问请求对象和响应对象来执行特定的操作,如记录日志、处理错误等。它们可以在应用程序中的特定路由或全局范围内使用。
1. 日志记录中间件
日志记录是一个常见的需求,用于记录应用程序的运行状态和用户请求的信息。下面是一个简单的日志记录中间件的实现:
const express = require('express');
const fs = require('fs');
const app = express();
// 日志记录中间件
const loggerMiddleware = (req, res, next) => {
const { method, url, ip } = req;
const currentTime = new Date().toISOString();
const logEntry = `${currentTime} - ${ip} - ${method} ${url}\n`;
fs.appendFile('logs.txt', logEntry, (err) => {
if (err) {
console.error('Failed to write log:', err);
}
});
next();
};
// 应用日志记录中间件
app.use(loggerMiddleware);
// 路由定义
app.get('/', (req, res) => {
// 处理当前路由的操作行为
// ...
res.send('Hello, World!');
});
// 启动服务器
app.listen(3000, () => {
console.log('Server started on port 3000');
});
在上述代码中,我们使用 fs.appendFile
方法将日志记录追加到日志文件 logs.txt
中。logEntry
变量包含了需要记录的日志信息,包括当前时间戳、用户的 IP 地址、请求方法和请求 URL。
通过调用 fs.appendFile
方法,我们将 logEntry
写入到日志文件中。如果写入失败,我们通过错误回调函数输出错误信息到控制台。
通过在应用程序中添加这段代码,每次用户访问路由时,都会将相应的日志信息追加到日志文件中。这样就实现了记录用户的访问时间、IP、路由地址、进入时间、离开时间和当前路由的操作行为,并存储在日志文件中。
请确保在使用 fs.appendFile
方法时,保持对文件的适当权限,并将日志文件的路径和名称根据实际情况进行调整。
2. 错误处理中间件
错误处理是保证应用程序稳定性和用户体验的重要环节。下面是一个简单的错误处理中间件的实现:
const express = require('express');
const app = express();
// 自定义错误处理中间件
const errorMiddleware = (err, req, res, next) => {
console.error(err); // 打印错误信息
res.status(500).send('Internal Server Error'); // 返回状态码为 500 的服务器内部错误响应
};
// 路由定义
app.get('/', (req, res) => {
throw new Error('Something went wrong'); // 抛出一个错误,模拟出错情况
});
// 应用错误处理中间件
app.use(errorMiddleware);
// 启动服务器
app.listen(3000, () => {
console.log('Server started on port 3000');
});
在上述代码中,我们定义了一个自定义的错误处理中间件 errorMiddleware
。它接收四个参数,其中第一个参数 err
表示捕获到的错误对象。在这个例子中,我们假设应用程序出现错误并抛出一个错误对象。
通过将错误处理中间件应用到应用程序中,我们可以捕获到路由处理函数中抛出的错误,并进行适当的处理。在这里,我们简单地打印错误信息并返回状态码为 500 的服务器内部错误响应。
4. 处理路由和路由参数
Express 提供了强大的路由处理功能,允许我们定义各种路由和处理函数之间的映射关系。我们可以根据请求的 URL 和 HTTP 方法来匹配对应的路由,并执行相应的处理函数。
在路由处理中,我们还可以使用路由参数来捕获动态的 URL 片段,并将其作为参数传递给处理函数。这使得我们可以实现灵活的路由控制,并根据不同的路由参数执行不同的操作。
通过处理路由和路由参数,我们可以构建出复杂而灵活的路由系统,实现不同路由路径和参数的请求处理。
下面是一个代码示例和案例,演示了如何使用 req
和 res
对象的属性和方法:
const express = require('express');
const app = express();
// 请求日志记录中间件
app.use((req, res, next) => {
console.log(`[${new Date().toISOString()}] ${req.method} ${req.url}`);
next();
});
// GET请求处理
app.get('/', (req, res) => {
res.send('Hello, World!');
});
// POST请求处理
app.post('/users', (req, res) => {
const { name, email } = req.body;
// 处理用户创建逻辑
res.status(201).json({ message: 'User created successfully' });
});
// 动态路由参数处理
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
// 根据用户ID查询用户信息
res.send(`User ID: ${userId}`);
});
// 查询参数处理
app.get('/search', (req, res) => {
const query = req.query.q;
// 根据查询参数进行搜索
res.send(`Search query: ${query}`);
});
// 错误处理中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Internal Server Error');
});
// 启动服务器
app.listen(3000, () => {
console.log('Server started on port 3000');
});
和前端交互经常使用的三个方法用来获取接口数据
req.params
、req.query
和 req.body
是 Express 框架中常用的属性,用于从请求对象 req
中获取参数和数据。
req.params
:req.params
属性包含了由路由定义的动态路由参数的值。它是一个对象,其中的属性名对应于路由定义中的参数名称。通过req.params
,我们可以在处理函数中访问和使用这些动态路由参数的值。例如,对于路由/users/:id
,可以通过req.params.id
来获取用户的 ID。req.query
:req.query
属性用于获取 URL 查询参数的值。查询参数是位于 URL 中?
符号之后的键值对形式的参数。通过req.query
,我们可以获取这些查询参数的值,并在处理函数中进行相应的操作。例如,对于 URL/users?id=1&name=John
,可以通过req.query.id
和req.query.name
分别获取id
和name
的值。req.body
:req.body
属性用于获取请求体中的数据。在处理 POST 请求或其他带有请求体的请求时,客户端通常会发送一些数据到服务器。这些数据可以是表单数据、JSON 数据等。通过req.body
,我们可以获取这些请求体中的数据,并在处理函数中进行相应的处理。但是在 Express 中,默认情况下,req.body
是未定义的,需要使用中间件(如express.json()
或express.urlencoded()
)来解析请求体中的数据。
常用的 req
和 res
对象的属性和方法:
req.method
:req.method
是一个属性,用于获取请求的 HTTP 方法(如 GET、POST、PUT、DELETE 等)。req.url
:req.url
是一个属性,用于获取请求的 URL。req.headers
:req.headers
是一个属性,用于获取请求的头部信息,返回一个包含所有头部字段的对象。req.cookies
:req.cookies
是一个属性,用于获取请求中的 Cookie。res.send()
:res.send()
是一个方法,用于发送响应给客户端。它可以接受不同类型的参数,如字符串、JSON 对象、HTML 页面等。res.status()
:res.status()
是一个方法,用于设置响应的 HTTP 状态码。res.json()
:res.json()
是一个方法,用于发送 JSON 响应给客户端。它会将传入的 JavaScript 对象自动序列化为 JSON 字符串,并设置相应的响应头部。res.redirect()
:res.redirect()
是一个方法,用于重定向请求到指定的 URL。res.sendFile()
:res.sendFile()
是一个方法,用于发送文件作为响应给客户端。
总结
在本章中,我们深入学习了 Express 框架中间件的概念和作用。我们了解了中间件的用途,并学习了如何使用内置中间件和自定义中间件来增强应用程序的功能。我们还实现了常见的中间件功能,如日志记录和身份验证,并学习了如何处理路由和路由参数。
通过理解和掌握 Express 中间件和路由的概念,我们能够构建出功能强大、灵活可扩展的 Web 应用程序。中间件提供了一种有效的方式来处理请求和响应,实现公共操作和功能。路由系统则允许我们定义不同路由路径和参数的处理逻辑,使得应用程序具备更好的灵活性和可维护性。
在下一章中,我们将进一步学习 Express 框架的高级特性,包括模板引擎、数据库集成和错误处理。这些知识将帮助我们构建更加完整和强大的 Web 应用程序。
转载自:https://juejin.cn/post/7248932545474543676