前端进阶之旅前端进阶之旅
  • 基础篇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 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库Node.js 原生 HTTP 限制请求体大小 413
NoNode.js服务端工程

原生 Node.js HTTP 如何限制请求体大小,而不是收完后才检查?

先把整个上传拼进内存再判断大小,拒绝得再准确也已经付出了最危险的一次分配。

前端进阶之旅 · 一题精讲更新于 2026.09.06
Node.js#服务端工程#测试#HTTP
先看核心答案读代码示例
理解线索

把预算放到数据进入的位置

  1. 入口预检校验路由策略和可用的长度声明
  2. 逐块计数在加入缓存前判断当前块是否超预算
  3. 结束处理只对完整且未超限的输入执行解析

下面函数只负责字节预算,不是完整 HTTP body parser。协议错误、413 响应、超时、连接关闭与异常监听仍由接入层负责。

核心回答

先记住这个答案

先按路由定义字节上限,合法 Content-Length 可用于提前拒绝,但读取过程中仍要累计实际 Buffer 字节数,不能只信请求头或字符串长度。每次收到块先检查剩余预算,超过后停止继续累积,释放已保存数据,并按协议状态选择发送 413 和关闭连接。分块传输也必须执行相同累计规则,压缩请求还需要独立限制解压后的体积。请求接收时间、并发数量和解析成本同样需要预算;单个 body 上限并不等于整个进程的内存上限。

  • 限制真实接收字节而不是字符数量
  • 声明长度可提前拒绝但不能替代流式计数
  • 超限分支同时处理内存、响应与连接生命周期

为什么头部和字符串长度都不够

请求可能使用分块传输而没有 Content-Length,代理也可能改变传输方式。长度声明可以减少明显超限请求的消耗,但实际数据仍要受约束,且应让 HTTP 解析器处理报文边界是否合法。

UTF-8 中文字符通常占多个字节,JavaScript 字符串 length 又按 UTF-16 码元计算。若限制的是内存和网络正文大小,应在解码前使用 Buffer 的 byteLength,避免多字节字符跨块时误计或错误拼接。

在保存块之前执行不可逆的超限判断

预算对象在首次超限后保持拒绝状态,避免调用方忽略一次失败又继续追加后面的块。使用剩余预算比较,避免先累加任意大数值;示例要求输入仍是字节块,不在中间调用 setEncoding。

接入 data 处理时,只有 accept 返回 true 才保存块。返回 false 后应进入唯一的拒绝分支并清空已有缓存;结束事件也必须检查拒绝状态,不能把超限输入作为一个较短的合法 JSON 继续解析。

独立的请求体字节预算TypeScript
export function createByteBudget(maxBytes: number) {
  if (!Number.isSafeInteger(maxBytes) || maxBytes < 0) {
    throw new RangeError('invalid byte limit');
  }
  let used = 0;
  let rejected = false;
  return {
    accept(chunk: Uint8Array) {
      if (rejected) return false;
      if (chunk.byteLength > maxBytes - used) {
        rejected = true;
        return false;
      }
      used += chunk.byteLength;
      return true;
    },
    get usedBytes() { return used; }
  };
}

例如上限 6 字节时,两块各含一个 UTF-8 中文字符可以接受,随后再来一个字节就拒绝。usedBytes 仅统计已接受部分,不宣称统计了超限后对端仍发送的全部流量。

拒绝后还要决定连接与并发成本

如果希望客户端看到 413,就不能先无条件 destroy 请求 socket 再期待响应完整送达。应在可写且尚未发出业务响应时设置拒绝响应和关闭策略,并为未关闭连接提供有界清理;协议已坏时可直接终止。

压缩正文可能很小而解压结果巨大,JSON 解析也可能产生额外对象内存。应分别限制压缩与展开体积、解析结构以及同时处理的请求数量,大文件则考虑受限流式处理或专用上传路径。

回答前,多想一步

容易答错的地方

收到 end 后才用 Buffer.concat 检查
此时所有块已经保存在内存里,concat 还可能分配另一份连续缓冲。应在每块进入缓存前限制预算,并在超限时清空引用;最终解析只处理确认完整且未超限的数据。
超限后无限读完并丢弃就算安全
这虽然不再积累正文,却仍可能长期占用连接、带宽和处理机会。拒绝流程还需要时间与连接上限,结合是否保持连接的策略明确停止条件,不能让攻击性慢上传无限延续。
试着用自己的话回答

面试官还会怎么问?

大文件上传也要用同一个很小上限吗?

应按路由和业务定义不同策略。小 JSON 接口适合有限内存解析,大文件应使用有界流式处理并限制总量、速率或时间,不能为了支持上传就取消所有接口的正文限制。

请求提前断开还能使用已收到的部分吗?

通常不能把截断的正文当作完整业务输入,应识别异常结束并放弃解析或提交。若业务支持分片上传,需要独立的分片编号、校验与完成协议,而不是依赖一次不完整 HTTP body。

为什么加了 body 限制仍可能内存很高?

并发请求会把单请求上限相乘,解压、字符串解码和对象解析还可能增加副本与对象开销。应观察同时活跃请求、解析阶段和缓存生命周期,结合进程预算限制并发及输入结构。

从一道题,走向一组知识

把知识连起来

服务端工程

Node.js 的 keepAliveTimeout、headersTimeout 和 requestTimeout 怎样区分?

为字节预算配合请求接收与连接等待时间上限。

服务端工程

Node.js HTTP 的 clientError 在什么阶段触发,监听后要负责什么?

区分正文业务限制与 HTTP 报文解析失败。

流与二进制

Writable.write 返回 false 表示写入失败吗,为什么要等 drain?

在上传后续写入慢目标时正确处理背压。

参考资料

  • Node.js 22:IncomingMessage 与 HTTP 生命周期
  • Node.js 22:Buffer 字节长度

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

本题目录
  1. 先记住这个答案
  2. 为什么头部和字符串长度都不够
  3. 在保存块之前执行不可逆的超限判断
  4. 拒绝后还要决定连接与并发成本
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

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

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