node.js根本学习-express框架-路由及中心件(十)

[复制链接]
发表于 2025-12-16 21:24:45 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
一、前言

Express 是一个简便、机动的 Node.js Web 应用框架。它基于 Node.js 的内置 HTTP 模块构建,提供了一系列用于构建 Web 应用步调和 API 的功能,使开辟者可以大概更高效地处置惩罚 HTTP 哀求和相应,专注于业务逻辑的实现。
其特点包罗简单易用、中心件机制丰富、路由体系机动等。通过利用 Express,可以快速搭建服务器,处置惩罚差异范例的哀求,如网页渲染、数据接口提供等多种功能。
二、路由

1. 根本的路由格式

一个根本的 Express 路由由 HTTP 方法(如app.get、app.post等)、路径(如'/'、'/about'等)和一个或多个回调函数构成。比方:
  1. app.get('/', (req, res) => {
  2.     res.send('Hello World!');
  3. });
复制代码
这里app.get表现处置惩罚 HTTP GET 哀求,'/'是哀求路径,(req, res) => {... }是回调函数。req代表哀求对象,包罗了哀求的相干信息,如哀求头、哀求参数等;res代表相应对象,用于发送相应给客户端,如res.send方法用于发送相应内容。
2. 路径匹配


  • 静态路径匹配:如app.get('/about', (req, res) => {... });,只有当哀求路径完全匹配/about时,这个路由才会被触发。
  • 动态路径匹配:可以利用参数来创建动态路由。比方,app.get('/users/:id', (req, res) => { const id = req.params.id; res.send(User ${id}); });,:id是一个动态参数,当哀求路径类似/users/1、/users/2等时,req.params.id可以获取到相应的参数值,用于根据差异的用户 ID 等动态信息返回差异的相应。
  • 路径参数的多种匹配方式
  • 可选参数:在路径中利用?来表现可选部分。比方app.get('ab?cd', (req, res) => {... });可以匹配ab大概abcd如许的路径。
  • 通配符匹配:利用*来表现匹配恣意字符序列。比方app.get('ab*cd', (req, res) => {... });可以匹配ab反面跟着恣意字符再接着cd的路径,如abxyzcd等。
  • 正则表达式匹配:可以直接在路径中利用正则表达式。比方app.get('/ab+cd', (req, res) => {... });匹配ab反面至少有一个字符再接着cd的路径,符合正则表达式ab+cd的模式。
3. 路由方法(HTTP方法)

Express 支持多种 HTTP 方法来界说路由,常见的有:

  • GET 哀求:用于从服务器获取数据。比方,获取网页内容、查询用户信息等场景。如app.get('/books', (req, res) => { // 查询册本信息并返回 });。
  • POST 哀求:通常用于向服务器提交数据,如提交表单数据、上传文件等。比方,app.post('/login', (req, res) => { // 处置惩罚用户登录信息提交 });。
  • PUT 哀求:用于更新服务器上的数据。比方,更新用户信息、修改文章内容等场景。app.put('/users/:id', (req, res) => { // 根据用户ID更新用户信息 });。
  • DELETE 哀求:用于删除服务器上的数据。比如删除用户记载、删除文件等。app.delete('/products/:id', (req, res) => { // 根据产物ID删除产物信息 });。
三、 Express 中心件

中心件是在哀求和相应周期中被调用的函数,它可以访问哀求对象(req)、相应对象(res)和应用步调的哀求 - 相应循环中的下一个中心件(next)。中心件可以实行各种使命,如日记记载、身份验证、数据预处置惩罚等,然后可以选择将哀求通报给下一个中心件大概路由处置惩罚函数。
1. 中心件的利用方式

单个中心件:在路由处置惩罚函数中,可以有一个或多个中心件。比方:
  1. app.get('/home', (req, res, next) => {
  2.     console.log('This is a middleware');
  3.     next();
  4. }, (req, res) => {
  5.     res.send('This is the home page');
  6. });
复制代码
这里第一个函数是中心件,它先打印一条日记,然后调用next()将控制权通报给下一个函数(这里是路由处置惩罚函数),用于发送相应。假如不调用next()函数,下一个中心件将不会被实行。
中心件数组:也可以将多个中心件组合成一个数组来利用。比方:
  1. const func1 = (req, res, next) => {
  2.     console.log('This is a middleware 1');
  3.     next();
  4. };
  5. const func2 = (req, res, next) => {
  6.     console.log('This is a middleware 2');
  7.     next();
  8. };
  9. const func3 = (req, res, next) => {
  10.     console.log('This is a middleware 3');
  11.     next();
  12. };
  13. app.get('/list', [func1, func2, func3], (req, res) => {
  14.     res.send('This is the list page');
  15. });
复制代码
当哀求/list路径时,会依次实行func1、func2、func3这三个中心件,末了实行路由处置惩罚函数来发送相应。
2. 中心件之间的传值

中心件可以通过req或res对象在中心件之间通报值。比方:
  1. const func4 = (req, res, next) => {
  2.     req.name = 'John';
  3.     res.age = 33;
  4.     next();
  5. };
  6. const func5 = (req, res, next) => {
  7.     const name = req.name;
  8.     const age = res.age;
  9.     res.send(`<h1>Hello ${name}, you are ${age} years old!</h1>`);
  10. };
  11. app.get('/hello', [func4, func5], (req, res) => {
  12. });
复制代码
在func4中心件中,通过req.name和res.age设置了值,然后在func5中心件中可以获取这些值来天生相应。
3. 差异范例的中心件

3.1 应用级中心件
通过app.use()方法来添加应用级中心件,它可以应用于整个应用步调大概特定的路径。假如没有指定路径,中心件会应用于全部的哀求路径。比方:
  1. const express = require('express');
  2. const app = express();
  3. app.use((req, res, next) => {
  4.     console.log('This middleware is called for every request');
  5.     next();
  6. });
  7. app.get('/hello', (req, res) => {
  8.     res.send('Hello World');
  9. });
  10. app.listen(3000, () => {
  11.     console.log('Server is running on port 3000');
  12. });
复制代码
在这个例子中,界说的中心件会在每个哀求到达服务器时被调用,它先打印一条日记,然后通过next()函数将哀求通报给下一个中心件大概路由处置惩罚函数。
3.2 特定路径的应用级中心件
可以指定中心件应用的路径,如许中心件只会对匹配该路径及其子路径的哀求起作用。比方:
  1. app.use('/admin', (req, res, next) => {
  2.     console.log('This middleware is for /admin and its sub - paths');
  3.     // 可以在这里进行权限验证等操作
  4.     next();
  5. });
  6. app.get('/admin/dashboard', (req, res) => {
  7.     res.send('Admin Dashboard');
  8. });
复制代码
当哀求/admin路径大概以/admin开头的子路径(如/admin/dashboard)时,中心件会被调用。这对于对特定模块或功能举行同一的预处置惩罚(如权限验证)非常有效。
3.3 路由中心件
路由中心件和应用级中心件类似,也是通过app.use()在特定路由路径下注册,在路由处置惩罚函数之前实行,用于对该路由的哀求举行预处置惩罚等操纵。比方:
  1. app.use('/api/users', (req, res, next) => {
  2.     console.log('This is a route - level middleware for /api/users');
  3.     // 可以在这里进行用户相关的预处理,如验证用户是否存在等
  4.     next();
  5. });
  6. app.get('/api/users', (req, res) => {
  7.     res.send('List of users');
  8. });
复制代码
这里的路由中心件会在处置惩罚/api/users路由的哀求之前被调用,用于对用户相干的哀求举行预处置惩罚。
3.4 错误处置惩罚中心件
错误处置惩罚中心件用于捕捉和处置惩罚在路由处置惩罚函数或其他中心件中抛出的错误。它的函数署名与平凡中心件略有差异,有四个参数(err, req, res, next),此中err参数用于吸收错误对象。错误处置惩罚中心件应该放在全部其他中心件和路由界说之后,如许才气捕捉它们抛出的错误。比方:
  1. app.use((err, req, res, next) => {
  2.     console.error(err.stack);
  3.     res.status(500).send('Something went wrong!');
  4. });
  5. app.get('/error - route', (req, res, next) => {
  6.     const error = new Error('This is a test error');
  7.     next(error);
  8. });
复制代码
在这个例子中,当哀求/error - route时,会在路由处置惩罚函数中创建一个错误对象并通过next(error)将错误通报给错误处置惩罚中心件。错误处置惩罚中心件会在控制台打印错误栈信息,然后向客户端返回一个状态码为500(服务器内部错误)的相应,消息为Something went wrong!。
3.5 内置中心件
**express.json():**用于分析application/json格式的哀求体。在处置惩罚 POST 或 PUT 哀求,且哀求体数据为 JSON 格式时非常有效。比方:
  1. app.use(express.json());
  2. app.post('/data', (req, res) => {
  3.     const data = req.body;
  4.     // 处理接收到的JSON数据
  5.     res.send('Data received');
  6. });
复制代码
当客户端发送一个application/json格式的 POST 哀求到/data路径时,express.json()中心件会主动将哀求体中的 JSON 数据分析为 JavaScript 对象,并挂载到req.body上,方便在路由处置惩罚函数中利用。
**express.urlencoded({ extended: false }):**用于分析application/x -www-form-urlencoded格式的哀求体。通常用于处置惩罚 HTML 表单提交的数据。比方:
  1. app.use(express.urlencoded({ extended: false }));
  2. app.post('/form-data', (req, res) => {
  3.     const formData = req.body;
  4.     // 处理接收到的表单数据
  5.     res.send('Form data received');
  6. });
复制代码
username=jun&password=123456这种格式的数据分析
3.6 第三方中心件
**morgan:**用于日记记载,它可以记载每个哀求的具体信息,如哀求方法、哀求路径、相应状态码等。比方:
  1. const morgan = require('morgan');
  2. app.use(morgan('combined'));
复制代码
这里morgan('combined')是一种日记格式选项,它会记载具体的哀求信息。morgan尚有其他日记格式,如'dev'(适当开辟情况)、'common'等,开辟者可以根据实际需求选择。
**cors:**用于办理跨域资源共享题目。比方:
  1. const cors = require('cors');
  2. app.use(cors({
  3.     origin: 'http://example.com',
  4.     methods: ['GET', 'POST'],
  5. }));
复制代码
这个设置允许来自http://example.com的哀求利用GET和POST方法举行跨域访问。可以根据具体的业务场景调解origin(允许的源)、methods(允许的哀求方法)等参数来满意跨域需求。
四、 模块化的路由中心件

express.Router是 Express 框架中的一个告急组件,它提供了一种模块化的方式来界说路由。利用Router可以将路由分组并封装到独立的模块中,这有助于构造大型应用步调的路由布局,使代码更加清晰、易于维护和扩展。
1. 创建和利用express.Router实例

创建实例:起首,必要创建一个Router实例。比方:
  1. const express = require('express');
  2. const router = express.Router();
复制代码
界说路由:在Router实例上可以像在主app对象上一样界说各种 HTTP 方法的路由。比方:
  1. router.get('/', (req, res) => {
  2.     res.send('This is the root of the sub - router');
  3. });
  4. router.post('/data', (req, res) => {
  5.     const data = req.body;
  6.     res.send(`Received data: ${data}`);
  7. });
复制代码
挂载到主应用:创建并界说好Router的路由后,必要将其挂载到主 Express 应用上。比方:
  1. const app = express();
  2. app.use('/api', router);
复制代码
这里将router挂载到/api路径下,这意味着router中界说的全部路由实际上是相对于/api路径的。比方,router中的'/'路由实际上对应的是/api/路径,'/data'路由对应的是/api/data路径。
2. 路由模块化的上风


  • 代码布局清晰:通过将相干的路由分组到差异的Router模块中,可以将一个大型应用的路由按照功能模块(如用户管理、产物管理、订单管理等)举行分别。比方,在一个电商应用中,可以有一个userRouter用于处置惩罚用户相干的路由(注册、登录、获取用户信息等),一个productRouter用于处置惩罚产物相干的路由(产物列表、产物详情、添加产物等),如许的代码布局更易于明白和维护。
  • 复用性增强:Router模块可以在差异的应用大概应用的差异部分复用。比如,一个通用的authRouter用于处置惩罚身份验证相干的路由(登录、验证 token 等),可以在多个差异的微服务大概应用模块中利用,只要它们遵照雷同的接口和认证机制。
  • 团队协作便利:在团队开辟中,差异的开辟职员可以负责差异的Router模块,如许可以并行开辟,镌汰代码辩论。比方,前端开辟职员和后端开辟职员可以分别开辟与用户界面交相互关的路由和与数据库操纵相干的路由,通过界说好的接口(如 API 路由)举行协作。
3. 中心件在express.Router中的利用

在Router级别利用中心件:可以在Router实例上利用中心件,这些中心件会应用到该Router所界说的全部路由上。比方:
  1. const loggerMiddleware = (req, res, next) => {
  2.     console.log(`Received a request for ${req.url}`);
  3.     next();
  4. };
  5. router.use(loggerMiddleware);
复制代码
这里界说了一个日记记载中心件loggerMiddleware,并通过router.use()将其应用到router上。如许,router中全部的路由在被访问时,都会先实行这个日记记载中心件。
在特定路由中利用中心件:也可以在Router的特定路由中利用中心件。比方:
  1. const authMiddleware = (req, res, next) => {
  2.     const token = req.headers.authorization;
  3.     if (!token) {
  4.         return res.status(401).send('Unauthorized: No token provided');
  5.     }
  6.     // 验证token的其他逻辑
  7.     next();
  8. };
  9. router.get('/protected - route', authMiddleware, (req, res) => {
  10.     res.send('This is a protected route');
  11. });
复制代码
在这个例子中,authMiddleware中心件只应用于/protected - route这个特定的路由。当访问该路由时,会先实行中心件举行身份验证,只有验证通事后才会实行路由处置惩罚函数。
4. 嵌套express.Router实例

express.Router实例可以举行嵌套,以创建更复杂的路由条理布局。这在构建具有多层级关系的 API 大概应用步调时非常有效。比方,在一个具有效户组和用户的应用中,可以先有一个groupRouter用于处置惩罚用户组相干的路由,在groupRouter内部再嵌套一个userRouter用于处置惩罚每个用户组内用户相干的路由。
  1. const groupRouter = express.Router();
  2. const userRouter = express.Router();
  3. // 定义用户组相关的路由
  4. groupRouter.get('/', (req, res) => {
  5.     res.send('List of groups');
  6. });
  7. groupRouter.post('/', (req, res) => {
  8.     res.send('Create a new group');
  9. });
  10. // 在用户组路由中嵌套用户路由
  11. userRouter.get('/', (req, res) => {
  12.     res.send('List of users in the group');
  13. });
  14. userRouter.post('/', (req, res) => {
  15.     res.send('Add a new user to the group');
  16. });
  17. groupRouter.use('/:groupId/users', userRouter);
  18. const app = express();
  19. app.use('/groups', groupRouter);
复制代码
在这个例子中,userRouter被嵌套在groupRouter内部。groupRouter处置惩罚用户组的根本路由,如获取用户组列表和创建新用户组。userRouter处置惩罚用户组内用户的相干路由,如获取用户组内用户列表和添加新用户到用户组。通过groupRouter.use('/:groupId/users', userRouter)将userRouter挂载到groupRouter的/:groupId/users路径下,如许就创建了一个嵌套的路由布局。当哀求/groups/1/users(假设1是用户组 ID)时,会先由groupRouter处置惩罚/groups/1部分的路由,然后将哀求通报给userRouter处置惩罚/users部分的路由。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表