第五部分:第五节 - Express 路由与中间件进阶:厨房的分工与异常处理

随着你的 Express 应用变得越来越大,所有的路由和中间件都写在一个文件里会变得难以管理。这时候就需要将代码进行拆分和组织。此外,一个健壮的后端应用必须能够优雅地处理错误和一些常见的 Web 开发问题,比如跨域。

路由模块化 (express.Router):

express.Router 是 Express 提供的一个迷你应用,它有自己的中间件和路由。你可以把处理某个特定资源的路由(比如所有用户相关的路由)放到一个单独的文件中,然后像中间件一样将其挂载到主应用上。这就像在厨房里为不同的菜品(资源)设立了专门的操作台(路由文件),每个操作台有自己的工作流程,但它们最终都属于整个厨房(主应用)。

创建一个新的文件,比如 routes/users.js

// routes/users.js
const express = require('express');
const router = express.Router(); // 创建一个 Router 实例// 这里可以定义用户相关的中间件,只应用于本路由文件中的路由
// router.use((req, res, next) => { console.log('用户路由中间件'); next(); });// 定义用户相关的路由
router.get('/', (req, res) => {// 处理获取所有用户的逻辑res.send('获取所有用户');
});router.get('/:userId', (req, res) => {const userId = req.params.userId;// 处理获取单个用户的逻辑res.send(`获取用户 ID: ${userId}`);
});router.post('/', (req, res) => {// 处理创建用户的逻辑res.send('创建新用户');
});// ... 其他用户相关的路由 (PUT, DELETE)module.exports = router; // 导出 router 实例 (CommonJS 方式)// 如果使用 ES Modules:
// export default router;

在你的主应用文件 app.js 中导入并使用这个路由模块:

// app.js
const express = require('express');
const app = express();
const port = 3000;// 导入用户路由模块
const usersRouter = require('./routes/users');
// const usersRouter from './routes/users.js'; // ES Modules// ... 其他中间件 (如 body-parser)// 将用户路由模块挂载到 /api/users 路径下
app.use('/api/users', usersRouter);// ... 其他路由和中间件// 启动服务器
app.listen(port, () => {console.log(`应用运行在 http://localhost:${port}`);
});// 现在访问 /api/users 会由 usersRouter 处理
// 访问 /api/users/123 会由 usersRouter.get('/:userId', ...) 处理

错误处理中间件:

在 Express 中,错误处理中间件有四个参数:(err, req, res, next)。当你在任何路由或普通中间件中调用 next(err) 并传入一个错误对象时,Express 会跳过后续的路由和中间件,直接进入错误处理中间件。这就像厨房里某个环节出了问题(比如菜烧焦了),不用继续整个流程,直接通知服务员(调用错误处理中间件)去处理这个“异常订单”。

通常,你会在所有路由和普通中间件的后面定义错误处理中间件,以捕获所有未被处理的错误。

// app.js (接着上面的代码)// ... 所有路由和普通中间件 ...// 404 错误处理 (放在所有有效路由之后)
app.use((req, res, next) => {res.status(404).send("对不起,找不到该页面!");
});// 错误处理中间件 (四个参数)
app.use((err, req, res, next) => {console.error("服务器端错误:", err.stack); // 打印错误堆栈到服务器控制台res.status(500).send("服务器内部出错!"); // 向客户端发送 500 状态码和错误信息
});// 在路由中模拟错误
app.get('/error-test', (req, res, next) => {// 模拟一个错误const myError = new Error("这是一个测试错误");next(myError); // 将错误传递给错误处理中间件
});

常用的第三方中间件:

Express 的生态系统非常丰富,有很多优秀的第三方中间件可以方便地集成。

  • morgan (日志记录): 记录所有收到的 HTTP 请求信息,对于调试和监控非常有帮助。就像餐厅里的订单记录系统。
    • 安装: npm install morgan
    • 使用: const morgan = require('morgan'); app.use(morgan('dev')); (dev 是预设的日志格式)
  • cors (跨域资源共享): 处理浏览器的同源策略限制,允许来自不同域的前端应用访问你的后端 API。这就像允许来自不同地区的顾客在你的餐厅点餐。
    • 安装: npm install cors
    • 使用: const cors = require('cors'); app.use(cors()); (允许所有跨域请求,也可以配置更精细的规则)
// app.js (接着上面的代码)const morgan = require('morgan');
const cors = require('cors');// 使用 morgan 中间件记录日志
app.use(morgan('dev'));// 使用 cors 中间件处理跨域
app.use(cors());// ... 其他路由和中间件 ...

小例子:模块化路由和全局错误处理

请参考上面关于 express.Router 和错误处理中间件的代码示例,将它们集成到一个完整的 Express 应用中。

小结: 使用 express.Router 可以将复杂的路由逻辑拆分到单独的文件中,提高代码的可组织性。错误处理中间件是捕获和处理应用错误的统一方式。morgancors 是两个非常常用的第三方中间件,分别用于日志记录和跨域处理。

练习:

  1. 在你的 Express 项目中,为之前的“书籍”资源创建一个单独的路由文件 (routes/books.js)。
  2. routes/books.js 中,使用 express.Router() 定义至少两个路由(例如 GET / 和 GET /:bookId)。
  3. 在主应用文件 app.js 中导入 routes/books.js 并将其挂载到 /api/books 路径下。
  4. 在主应用中添加一个 404 错误处理中间件(放在所有有效路由之后)。
  5. 在主应用中添加一个全局错误处理中间件,当接收到错误时,记录错误到控制台并向客户端发送 500 状态码。
  6. 安装并使用 morgan 中间件记录所有请求日志。
  7. 安装并使用 cors 中间件,允许所有来源的跨域请求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/81861.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

萌新联赛第(三)场

C题 这道题用暴力去写想都不要想,一定超时,于是我们需要优化,下面是思路过程: 如图,本题只需找到x的因数个数和(n-x)的因数个数,这两个相乘,得到的就是对于这个x来说组合的个数,且x…

【Android构建系统】如何在Camera Hal的Android.bp中选择性引用某个模块

背景描述 本篇文章是一个Android.bp中选择性引用某个模块的实例。 如果是Android.mk编译时期,在编译阶段通过某个条件判断是不是引用某个模块A, 是比较好实现的。Android15使用Android.bp构建后,要想在Android.bp中通过自定义的一个变量或者条件实现选…

【OneNET】_01_使用微信小程序通过新版OneNET平台获取STM32设备信息并进行控制

【OneNET】_01_使用微信小程序通过新版OneNET平台获取STM32设备信息并进行控制 一、 前言1.1 OntNET硬件方面: STM32F103C8T6 ESP01S教程 1.2 微信小程序方面 二、STM32代码部分修改三、微信小程序修改的部分四、小笔记(个人杂记)4.1 OneNETOneNET物联网…

用 python 编写的一个图片自动分类小程序(三)

图片自动分类识别小程序记录 2025/5/18 0:38修改程序界面,增加一些功能 用 python 编写的一个图片自动识别分类小程序。 操作系统平台:Microsoft Windows 11 编程语言和 IDE:python 3.10 Visual studio code 一:图片自动分…

嵌入式硬件篇---SGP30 气体传感器

文章目录 前言一、SGP30 气体传感器详解(一)基本概述(二)工作原理传感器结构检测机制自校准功能(三)主要特性(四)应用场景智能家居空气质量检测仪汽车行业商业建筑二、TVOC 与 eCO2 的含义(一)TVOC(总挥发性有机化合物)定义危害健康标准(二)eCO2(等效二氧化碳)…

【原创】ubuntu22.04下载编译AOSP 15

安装依赖的库,顺便把vim 也安装一下 sudo apt-get install vim sudo apt-get install git gnupg flex bison build-essential zip curl zlib1g-dev libc6-dev-i386 x11proto-core-dev libx11-dev lib32z1-dev libgl1-mesa-dev libxml2-utils xsltproc unzip font…

防止勒索病毒的兜底方案——备份

勒索病毒入侵会对您的业务数据进行加密勒索,导致业务中断、数据泄露、数据丢失等,从而带来严重的业务风险。 防止勒索病毒有三个方向: 1)实时防御已知勒索病毒 各个云厂商的云安全中心实现了对大量已知勒索病毒的实时防御。在服务…

es在已有历史数据的文档新增加字段操作

新增字段设置默认值 场景 在已经有大量数据的索引文档上,增加新字段 技术实现 一.更新索引映射 通过PUT请求显式定义新字段类型,确保后续写入的文档能被正确解析 PUT /文档名/_mapping {"properties": {"字段名1": {"type…

留给王小川的时间不多了

王小川,这位头顶“天才少年”光环的清华学霸、搜狗输入法创始人、中国互联网初代技术偶像,正迎来人生中最难啃的硬骨头。 他在2023年创立的百川智能,被称为“大模型六小虎”之一。今年4月,王小川在全员信中罕见地反思过去两年工作…

深入掌握MyBatis:连接池、动态SQL、多表查询与缓存

文章目录 一、MyBatis连接池1.1 连接池的作用1.2 MyBatis连接池分类 二、动态SQL2.1 if标签2.2 where标签2.3 foreach标签2.4 SQL片段复用 三、多表查询3.1 多对一查询(一对一)3.2 一对多查询 四、延迟加载4.1 立即加载 vs 延迟加载4.2 配置延迟加载 五、…

TDesign AI Chat - Vue3.x 可用!腾讯出品的 AIGC 交互对话组件,免费开源、包含设计资源

各位前端开发者有遇到做 AI Chat 项目的聊天交互界面需求了吗?TDesign 出品的这个组件很不错,推荐给大家。 TDesign AI Chat 是 TDesign 为 AIGC 场景开发的 UI 系列组件中的一部分,主要用于开发目前非常流行的 ChatBot 对话交互场景。最近 …

spring -MVC-02

SpringMVC-11 - 响应 在 SpringMVC 中,响应是服务器对客户端请求的反馈,它可以以多种形式呈现,包括视图名称、ModelAndView 对象、JSON 数据以及重定向等。以下是对 SpringMVC 中不同响应类型的详细介绍: 1. 视图名称 通过返回…

老旧设备升级利器:Modbus TCP转 Profinet让能效监控更智能

在工业自动化领域,ModbusTCP和Profinet是两种常见的通讯协议。Profinet是西门子公司推出的基于以太网的实时工业以太网标准,而Modbus则是由施耐德电气提出的全球首个真正开放的、应用于电子控制器上的现场总线协议。这两种协议各有各的优点,但…

ubuntu下docker安装mongodb-支持单副本集

1.mogodb支持事务的前提 1) MongoDB 版本:确保 MongoDB 版本大于或等于 4.0,因为事务支持是在 4.0 版本中引入的。 2) 副本集配置:MongoDB 必须以副本集(Replica Set)模式运行,即使是单节点副本集&#x…

【前端开发】Uniapp日期时间选择器:实现分钟动态步长设置

技术栈 Uniapp + Vue3 + uView年份显示前后一年,分钟动态设置间隔效果图 主体显示<view class="uni-row-between selector"><view class="uni-flex-1 left" @click="!props.disabled && openPicker()"><uni-iconscolor=…

iOS 蓝牙开发中的 BT 与 BLE

在 iOS 开发者的语境里&#xff0c;大家把 BT 和 BLE 当成两种不同的蓝牙技术在谈——它们来自同一个 Bluetooth 规范&#xff0c;但面向的场景、协议栈乃至 Apple 提供的 API 都截然不同。 缩写全称 / 技术名称规范层叫法iOS 支持现状典型用途BTBluetooth Classic&#xff08…

Flink CEP是什么?

Apache Flink 的 CEP&#xff08;Complex Event Processing&#xff0c;复杂事件处理&#xff09; 是 Flink 提供的一个库&#xff0c;用于在无界数据流中检测符合特定模式的事件组合。 &#x1f3af; 一、什么是 CEP&#xff1f; ✅ 定义&#xff1a; CEP 是一种从连续的数据…

ARM (Attention Refinement Module)

ARM模块【来源于BiSeNet】&#xff1a;细化特征图的注意力&#xff0c;增强重要特征并抑制不重要的特征。 Attention Refinement Module (ARM) 详解 ARM (Attention Refinement Module) 是 BiSeNet 中用于增强特征表示的关键模块&#xff0c;它通过注意力机制来细化特征图&…

AR0144CSSC20SUKA0-CRBR——1/4英寸 1.0 MP 高性能CMOS图像传感器解析

产品概述&#xff1a; AR0144CSSC20SUKA0-CRBR 是一款1/4 英寸&#xff0c;1.0 Mp CMOS 数字图像传感器&#xff0c;带有 1280H x 800V 有效像素阵列 全局快门CMOS数字图像传感器&#xff0c;它结合了新型的创新全局快门像素设计&#xff0c;适用于准确快速的移动场景捕捉。该…

深入理解递归算法:Go语言实现指南

深入理解递归算法&#xff1a;Go语言实现指南 引言 递归是编程中一种优雅而强大的算法思想&#xff0c;通过函数自我调用的方式解决复杂问题。本文将使用Go语言演示递归的核心原理&#xff0c;并通过典型示例帮助开发者掌握这一重要技术。 一、递归基础概念 1.1 递归定义 递归…