DEBUG.WIKI
阿里云;从建站到云上业务;云服务器 · 数据库 · 对象存储;查看产品 →
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →

Express redirect 报 Content-Length 不能与 Transfer-Encoding 同时出现

Express 5.3.0 redirect 可能在已有 Transfer-Encoding 时仍写入 Content-Length,导致客户端拒绝响应。移除普通跳转中不必要的手工传输头,检查原始响应与跟随跳转。

Express 接口调用 res.redirect() 后,Node 客户端报 Content-Length can't be present with Transfer-Encoding。如果前面的中间件手动设置了 Transfer-Encoding: chunked,应检查重定向分支有没有又写入 Content-Length。

Express 5.3.0 的 redirect 根据客户端接受的格式生成一段短正文,随后无条件写入它的字节长度。res.send 对传输编码的处理不同,不能因为普通响应正常,就推断重定向也会自动消除冲突。

普通重定向不需要预设分块传输

如果应用本来只是重定向,没有必须手工控制传输编码的协议需求,应移除自己预设的 Transfer-Encoding,让 HTTP 栈按实际正文决定消息边界。例如在尚未发送响应头的重定向分支中:

app.get('/old-page', (req, res) => {
  res.removeHeader('Transfer-Encoding');
  return res.redirect(302, '/new-page');
});

这是已有 app 的路由片段,目标应是应用允许的真实路径。不要把未校验的外部输入直接作为跳转地址;这处头字段修订不替代原来的访问控制与跳转目标约束。

应同时定位哪个中间件写了传输头。若它对所有响应统一设置,修正其适用范围通常比每条路由再补一次删除更容易维护。响应头已经发出或正文已经开始传输时,不能再靠 removeHeader 改写此前的消息边界。

不要只删除长度或关闭客户端检查

在调用 redirect 之前删除 Content-Length 没用,因为该方法之后还会重建它。等到发送完再修改响应头也太晚,可能转成另一种 headers sent 错误。

确实需要保留特定传输方式的系统,应在受控响应构造边界或受审查的依赖补丁中处理整套 framing,保证只存在一种正确长度表示;不要手工拼接互相矛盾的头与分块字节。原有代理、HTTP 版本与后续中间件也要一起核对。

这与Nginx 对请求分块做正常转换不同。那里讨论两条连接上的请求体表达,本题是同一条响应同时声明互斥的消息边界,客户端拒绝是有实际协议依据的,不能靠放松解析检查解决。

截至 2026 年 10 月 26 日,正式 Express 5.3.0 的 redirect 仍无条件设置长度。临时改动前保留原中间件配置;撤回时恢复对应设置,并重新核对重定向分支,不能只回退业务 URL。

验收时先观察不自动跟随跳转的原始响应,确认状态、Location 与正文长度表达正确,再检查客户端按原策略跟随后得到预期资源。覆盖普通 GET、HEAD 和其他会经过该中间件的响应,避免只修了一个跳转却改变正常下载或流式接口。