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

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

路由模块化 (express.Router):

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

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

javascript 复制代码
// 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 中导入并使用这个路由模块:

javascript 复制代码
// 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 会跳过后续的路由和中间件,直接进入错误处理中间件。这就像厨房里某个环节出了问题(比如菜烧焦了),不用继续整个流程,直接通知服务员(调用错误处理中间件)去处理这个"异常订单"。

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

javascript 复制代码
// 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()); (允许所有跨域请求,也可以配置更精细的规则)
javascript 复制代码
// 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 中间件,允许所有来源的跨域请求。
相关推荐
爆米花byh9 小时前
在RockyLinux9环境的Kafka4.1.1单机版安装(无ZK依赖)
中间件·kafka
爆米花byh10 小时前
在RockyLinux9环境的Storm2.8.3单机版安装
linux·中间件·storm
PD我是你的真爱粉10 小时前
FastAPI中间件与路由
中间件·fastapi
会算数的⑨11 小时前
Kafka知识点问题驱动式的回顾与复习——(一)
分布式·后端·中间件·kafka
小白不想白a21 小时前
消息队列--包括面试常考题/运维监控指标
中间件
金刚猿21 小时前
01_虚拟机中间件部署_root 用户安装 docker 容器,配置非root用户权限
docker·中间件·容器
Hello.Reader1 天前
Rocket Fairings 实战把全局能力做成“结构化中间件”
中间件·rust·rocket
岁岁种桃花儿2 天前
Kafka从入门到上天系列第一篇:kafka的安装和启动
大数据·中间件·kafka
波波0073 天前
每日一题:中间件是如何工作的?
中间件·.net·面试题
玄同7653 天前
LangChain 1.0 框架全面解析:从架构到实践
人工智能·深度学习·自然语言处理·中间件·架构·langchain·rag