普通视图

发现新文章,点击刷新页面。
昨天以前首页

Express 子路由、静态资源与错误处理详解

作者 coderklaus
2025年6月30日 18:12

在实际开发中,随着项目规模扩大,路由和中间件的数量会迅速增长。如果所有路由都写在同一个文件里,代码将变得难以维护。Express 提供了子路由(Router)中间件机制,可以帮助我们实现模块化开发、静态资源托管和高效的错误处理。下面详细介绍这些内容。

一、子路由(Router)

1. 为什么要使用子路由?

当路由数量较多时,推荐将不同业务模块的路由拆分到不同文件或目录(如 routerroutes 文件夹),每个模块对应一个子路由。这样可以做到高内聚、低耦合,提升项目可维护性和可扩展性。

2. express.Router 的原理

express.Router() 本质上是一个“迷你版”的 Express 应用,拥有完整的中间件和路由系统。你可以为它单独定义路由、中间件、参数处理等,最后将其挂载到主应用的某个路径下。

3. 子路由的使用示例

import express from 'express'

const app = express()

// 创建子路由对象
const userRouter = express.Router()

// 定义子路由
userRouter.get('/list', (req, res) => {
  // req.url 是子路由基准路径之后的部分
  // req.baseUrl 是子路由的基准路径
  // req.originalUrl 是原始请求路径
  res.json({
    url: req.url,
    path: req.path,
    baseUrl: req.baseUrl,
    originalUrl: req.originalUrl,
    params: req.params,
    query: req.query
  })
})

userRouter.post('/create', (req, res) => res.end(req.url))
userRouter.patch('/:id', (req, res) => res.end(req.url))

// 挂载子路由到主应用
app.use('/users', userRouter)

app.listen(3000)

小结:

  • 子路由路径必须以 / 开头。
  • 请求到 /users/list 时,userRouter 内的 /list 路由会被匹配。
  • 这样拆分后,主文件只需负责路由挂载,具体逻辑分散在各自模块,结构清晰。

二、静态资源托管

Web 项目通常需要对外暴露静态文件(如图片、CSS、JS、上传文件等)。Express 提供了内置中间件 express.static(),可将指定目录设为静态资源目录。

1. 使用方法

import express from 'express'

const app = express()

// 设置静态资源目录(可多次调用,支持多个目录)
app.use(express.static('./uploads'))
app.use(express.static('./build'))

app.listen(3000)
  • 访问 http://localhost:3000/头像.jpg,会自动查找 uploadsbuild 目录下的 头像.jpg 文件。
  • 静态资源中间件会优先返回第一个匹配到的文件。

建议:
将上传目录、前端打包目录等都设置为静态资源目录,便于统一管理和访问。

三、错误处理机制

后端服务不可避免会遇到各种异常情况。Express 提供了灵活的错误处理机制,主要包括两种方式:

1. HTTP 状态码 + 错误信息

这是最常见的处理方式。直接返回标准 HTTP 错误码(如 404、500),并在响应体中说明错误原因。

res.status(404).send('资源未找到')
  • 优点:符合 HTTP 标准,前端可直接根据状态码判断。
  • 缺点:有时无法满足复杂业务需求。

2. 业务自定义错误码

有些团队喜欢所有接口都返回 200 状态码,通过响应体中的自定义 code 字段区分业务成功/失败。

res.json({
  code: 404,
  message: '用户不存在',
  data: null
})
  • 优点:前后端约定灵活,业务错误粒度可控。
  • 缺点:不符合 RESTful 风格,需前端配合解析。

3. 错误处理中间件

Express 允许通过特殊格式的中间件统一处理错误(即错误处理中间件)。只要在 next() 里传递参数,Express 就会跳过后续普通中间件,直接进入错误处理中间件。

import express from 'express'

const app = express()

app.use(express.json())

app.post('/login', (req, res, next) => {
  const { name, password } = req.body
  if (!name || !password) {
    // 传递错误码到错误处理中间件
    next(-1001)
  } else {
    res.send('登录成功')
  }
})

// 错误处理中间件(参数比普通中间件多一个 err)
app.use((err, req, res, next) => {
  switch (err) {
    case -1001:
      res.status(400).send('用户名或密码不能为空')
      break
    case -1002:
      res.status(401).send('用户名或密码错误')
      break
    case -1003:
      res.status(404).send('用户名不存在')
      break
    default:
      res.status(500).send('服务器内部错误')
  }
})

app.listen(3000)

建议:

  • 错误处理中间件应放在所有路由之后。
  • 可结合日志系统,记录错误详情,便于排查问题。
  • 复杂项目可对错误码、错误信息进行统一管理。
❌
❌