先记住这个答案
next() 不带参数时,控制权传递给当前路径的下一个中间件或路由处理器。next('route') 仅对 app.METHOD 或 router.METHOD 注册的路由处理器有效,跳过当前路由数组中的剩余回调,转而匹配下一个路由。next(err) 会跳过所有普通中间件,直接进入错误处理中间件(需四参数签名)。三者分别对应常规流程、单路由跳转和异常捕获。
- next() 继续当前栈下一个中间件
- next('route') 跳过本路由剩余回调
- next(err) 跳过普通中间件进入错误链
next() 与 next('route') 的执行栈差异
Express 内部维护一个中间件列表,每个请求按顺序执行。next() 无参数时,它让 Express 从当前中间件的位置继续寻找下一个匹配的中间件,通常使请求沿预设链推进。若当前回调不调用 next(),则链路被挂起,可能造成响应延迟。
next('route') 是 Express 特有的路由控制语法,当你在由 app.get、router.post 等方法注册的处理器数组中调用它,Express 会立即停止执行当前数组的剩余回调,转而在已注册的路由表里寻找下一个与路径匹配的路由。官方文档明确它仅在 app.METHOD() 或 router.METHOD() 注册的函数中有效;在 app.use() 挂载的中间件中调用不会实现跳到下一路由的效果,不应依赖。
next(err) 接受任意 Error 或值,Express 会把除保留字符串 'route' 以外的任何参数(包括其他字符串)视为错误,跳过所有普通中间件与路由处理器,直接调用带 err 参数的中间件。错误链中若没有四参数中间件,默认错误处理器会返回 500。字符串 'route' 是保留字,专用于路由跳转。
按用户 ID 跳转路由的条件分支
假设有 app.get('/user/:id', verify, render) 以及后续 app.get('/user/:id', fallback)。当请求用户 ID 等于 '0' 时,在 verify 回调中调用 next('route'),则 render 不会执行,直接落到 fallback 处理,返回特殊响应。
原因是 next('route') 让 Express 在当前路由栈(即 [verify, render])中中止,并从下一匹配的路由开始继续。若改用 next(),render 也会被调用,而若 render 已经发送响应,后续路由不会再触发,流程不符合需求。
具体代码逻辑:verify 中先检查 req.params.id,若为 '0' 则 next('route'),否则 next()。这样可分离主流程与降级路径,但需确保 next('route') 后确实还有下一路由,否则请求将落入默认 404 处理。
调用方式的适用边界与失效条件
next('route') 只能在由 app.METHOD 或 router.METHOD 注册的中间件栈内生效;在 app.use() 挂载的中间件中调用不会跳到下一个路由,官方文档明确其仅适用于路由方法注册的函数,因此需严格区分中间件类型。
在 Express 4 中,当一个异步操作抛出异常时,直接 throw 并不会被 Express 捕获,必须调用 next(err) 将错误传递到错误处理中间件(Express 5 会自动将 rejected Promise 交给错误处理中间件)。若在路由处理器中误用 next() 传入除 'route' 以外的值(如错误对象),该值会被视为 err,导致错误链触发,而不是路由跳转。
若调用 next() 后当前函数仍继续执行并发送响应,会造成重复响应错误。应在调用 next() 后立刻 return,避免代码继续运行。
容易答错的地方
- 认为 next('route') 可用于任何中间件
- 实际上 next('route') 仅对 app.METHOD() 或 router.METHOD() 注册的路由处理器有效;在 app.use() 挂载的中间件中调用不会实现跳到下一路由的效果。需要跨路由跳转时,必须用路由方法注册处理器,不能依赖它在普通中间件中工作。
- 以为 next(err) 会跳过当前之后的同栈中间件后仍回当前路由
- next(err) 直接进入错误处理中间件,不再继续当前普通中间件或后续路由处理器。错误链是专门处理异常的独立栈,不参与常规路由流程。
面试官还会怎么问?
如果 next('route') 之后没有其他匹配的路由会发生什么?
请求将留在该路径的处理队列并最终落入默认 404 处理,因为不再有匹配项。Express 默认调用最终处理逻辑,通常返回 404。
如何判断应该使用 next('route') 还是条件分支?
当当前路由有多个回调且后续回调不应执行时使用 next('route');若仅需在当前回调中改变处理逻辑,则用 if/else 调用 next() 或直接结束响应。
在异步函数中直接 throw 能否触发错误中间件?
Express 4 不会自动捕获异步函数中的异常,抛出的错误会成为未处理的 Promise 拒绝,请求一直挂起;Express 5 起会自动把 rejected Promise 交给错误处理中间件。因此在 Express 4 中异步错误必须显式调用 next(err) 或用包装器转发。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。