You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express.js嵌套路由返回404 Not Found问题求助

Express.js嵌套路由404问题解决

开发REST API时,配置Express嵌套路由后,请求/accounts/:account-id/cashflows这类URL会返回404 Not Found错误,但当account-id参数为空时(比如请求/accounts//cashflows)却不会报错。使用的Express版本为^4.19.2。


路由入口文件(src/routes/index.ts)

import { Router } from 'express';

import accountRouter from './accounts.js';
import cashflowRouter from './cashflows.js';

const api = () => {
  const router = Router();

  // cashflows <- 404
  router.use('/accounts/:account-id/cashflows', cashflowRouter());

  // accounts <- 正常工作
  router.use('/accounts', accountRouter());

  return router;
}

export default api;

现金流路由文件(src/routes/cashflows.ts)

import { Router } from 'express';

import cashflows from '../controllers/cashflows.js';

const api = () => {
  const router = Router();

  // GET /accounts/:account-id/cashflows <- 获取所有现金流
  router.get('/', cashflows.find);

  // GET /accounts/:account-id/cashflows/:id <- 获取单个现金流
  router.get('/:id', cashflows.findOne);

  // POST /accounts/:account-id/cashflows <- 添加现金流
  router.post('/', cashflows.add);

  // PATCH /accounts/:account-id/cashflows/:id <- 更新现金流
  router.patch('/:id', cashflows.update);

  // DELETE /accounts/:account-id/cashflows/:id <- 删除现金流
  router.delete('/:id', cashflows.remove);

  return router;
}

export default api;

已尝试的方案

  • 将cashflowRouter作为accountRouter的中间件,并设置mergeParams: true,无效。
  • 直接在index.ts中定义嵌套路由(如下)可以正常工作,但不符合预期的模块化实现:
router.get('/accounts/:id/example', (req, res) => {
    res.json(req.params.id);
})

该测试路由放置在所有其他路由之前。


问题原因

Express的路由参数命名不允许包含连字符(-),仅支持字母、数字和下划线。/:account-id这种带连字符的参数定义会导致Express无法正确解析路由规则,进而无法匹配请求,最终请求会落到后面的/accounts路由,而accountRouter中没有对应/cashflows的处理逻辑,因此返回404。

当account-id参数为空时,URL变为/accounts//cashflows,Express会将连续的斜杠视为单个斜杠,此时请求路径相当于/accounts/cashflows,由于原路由规则的解析问题,反而触发了非预期的匹配(并非正确逻辑)。


解决方案

1. 修正路由参数命名

将路由参数中的连字符改为下划线或驼峰命名,例如account_id或accountId:
修改index.ts中的路由挂载代码:

router.use('/accounts/:accountId/cashflows', cashflowRouter());

2. 开启参数合并(如需在子路由访问父参数)

如果需要在cashflowRouter中访问accountId参数,需要在创建子路由时设置mergeParams: true:
修改cashflows.ts中的路由创建代码:

const router = Router({ mergeParams: true });

这样在cashflows控制器中就能通过req.params.accountId获取到父路由的参数。

3. 确认路由挂载顺序

确保嵌套路由的挂载顺序在基础路由之前(当前代码已符合要求),避免基础路由先匹配请求导致嵌套路由无法生效。


内容的提问来源于stack exchange,提问作者Kamil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 02:23:15