前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Express 中间件忘记调用 next 请求挂起
全栈全栈开发Express 服务

Express 中间件既不发响应也不调用 next() 会导致什么后果,如何排查?

Express 中间件既不发送响应也不调用 next() 会令请求永久停留在当前层,连接悬空且不会自动释放,客户端超时后服务端仍可能占用资源。排查的关键是确认控制流是否被截断,可用日志分段、超时护栏定位。

前端进阶之旅 · 一题精讲更新于 2026.09.05
全栈开发#Express 服务#可观测性
先看核心答案
理解线索

控制流未交接

  1. next 移交调用 next() 进入栈中下一层
  2. res 终结发送 res 响应即结束请求周期
  3. 不交也不发请求挂起,连接被白白占用

中间件可以省略 next 而直接 res.end,但不能同时跳过两者。

核心回答

先记住这个答案

中间件靠 next() 移交控制,或调用 res.end/res.send 结束请求。若两者皆无,请求永不结束:后续中间件和路由不会执行,响应不发,连接保持打开且不会自动释放,客户端超时后服务端资源也未必及时清理。定位时加入口日志和出口日志,或包一个 setTimeout 中间件,超时后打印当前栈和 URL 即可找出漏掉 next() 的处理函数。

  • 中间件必须以 res 或 next 结束控制流
  • 挂起连接不会自动释放,超时后仍可能占资源
  • 日志与超时中间件能快速定位漏调函数

为什么请求会挂起

Express 的中间件栈要求每层完成后调用 next() 移交,或通过 res 发送响应结束。若两者都缺,控制流停在该层,后续中间件与路由不会运行,也没有响应返回。连接保持打开,等待永远不会发生的数据。

从事件循环看,该请求的 socket 没有被关闭,服务器资源被长期占用。虽然不会抛出异常,但高并发下挂起请求会耗尽文件描述符,导致新连接被拒。给每个中间件入口和出口打日志,能直观看出停在哪个函数。

用户校验服务中的漏调分支

用户模块的校验中间件对请求头 token 异步解码,成功后查询数据库用户,若查到则 req.user 赋值并调用 next();若查不到,代码只写了一条日志后 return,没有 next 也没发 res。当客户端携带不存在的 token 时,请求挂起无响应。

排查时先在该中间件前后打印标记,前端发现请求在第二个标记前消失,说明卡在回调内。接着给 app.use 挂一个超时包装器,用 setTimeout 在 8 秒后 res.status(504).send('timeout') 并输出调用栈,日志显示当前中间件名,修复方法是查询为空时补 res.status(404).json(...) 或调用 next(),但为符合语义,补响应是正解。

适用边界与失效情形

若中间件已经调用 res.end(),即使没调 next 也不会挂起,因为响应结束已使 HTTP 周期完成。若中间件内部发生异步异常但未传给 next,也可能出现同类无响应现象,但那是错误处理缺陷而非简单的 next 漏调。超时中间件只能捕捉同步路径上的截断,对于嵌套太深的 Promise 链路需要额外包裹。

客户端超时断开后,服务端未必立刻关闭 socket,挂起连接可能仍占着资源。部署在反向代理后可用代理的 upstream_timeout 兜底,但应用层仍应在 res 的 close 事件里做清理。要彻底避免,可在开发环境强制所有中间件代码 lint,禁止既不 send 也不调用 next 的函数存在。

回答前,多想一步

容易答错的地方

以为 next 必须调用才正确
事实上若已经发送响应,不调用 next() 也允许,只是会让当前中间件成为终点。常见误区是认为不调用 next 必错,却忽略了需要这种短路场景。真正的错误是既未发响应又未调用 next,造成后续无从清理。
客户端超时即可清理连接
客户端超时只是停止等待,TCP 连接是否关闭取决于底层 keepAlive 和 Node 设置,如果没显式结束,服务端 socket 不会被释放。大量挂起连接会耗尽文件描述符,最终必须重启进程。生产环境要主动监测半关闭连接。
试着用自己的话回答

面试官还会怎么问?

如何全局捕获请求挂起而不修改每个中间件?

可把整个业务中间件包在 async 函数里,用 Promise.race 与超时相争,超时后打印堆栈并强制响应。但 Express 4 的 next 不是 Promise 兼容,需配合包装函数。

调用 next('route') 与不调用 next 有何不同?

next('route') 明确跳转到下一个同方法路由,控制权仍在传递,不会挂起;不调用 next 则是控制流完全终止。注意 next('route') 仅适用于通过 app.METHOD 或 router.METHOD 加载的中间件,不适用于 app.use。

用浏览器访问挂起请求,多久会得到错误?

取决于客户端超时设置。浏览器通常约 30 秒到 1 分钟,curl 无限等待。服务端若长期无响应,nginx 默认 proxy_read_timeout 为 60 秒,但不等同于 Node 释放连接。

从一道题,走向一组知识

把知识连起来

Express 服务

Express 中调用 next()、next('route') 和 next(err) 分别改变什么控制流?

next() 是控制流转的核心,理解它的各种调用形态是排查挂起与短路的前提。

Express 服务

Express 中间件按什么顺序执行,顺序写错会发生什么?

中间件顺序错误可能造成调用位置不对,但漏调 next 会在顺序日志检查中最直观暴露。

参考资料

  • Using middleware

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为什么请求会挂起
  3. 用户校验服务中的漏调分支
  4. 适用边界与失效情形
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑