Express 为什么返回 Content-Type: false
Express 对 Content-Type 调用 MIME 转换,未知简写可能成为字符串 false。使用与实际内容一致的完整媒体类型,或明确采用 res.type 的二进制回退。
下载接口返回了 Content-Type: false,代码里却没有写过字符串 false。若响应使用 Express 的 res.set('Content-Type', ...),检查传进去的是完整媒体类型,还是一个无法识别的文件扩展名或自定义简写。
在 Express 5.2.1 和 5.3.0 的正式实现中,设置这个特殊响应头会经过 MIME 类型转换。未知简写转换失败得到布尔值 false,随后写入响应头时成为字符串。直接换一种未知简写,不能解决它。
通用 set 方法也会转换 Content-Type
例如,下面的 some-custom-type 并不是完整媒体类型,也不是已知扩展名:
app.get('/download', (req, res) => {
res.set('Content-Type', 'some-custom-type');
res.send('hello');
});
Express 对 Content-Type 的处理不同于普通自定义头:它调用 MIME 转换函数,给已知类型补充必要的字符集等信息。转换函数不认识这个值时返回 false,而这条路径没有为失败结果提供回退。
这不是服务器替你推断出了某种叫 false 的文件格式。媒体类型应有 type/subtype 结构,例如 text/plain 或 application/octet-stream。即使绕开 Express 的转换,把不含斜杠的未知值原样写出去,也没有得到合法的媒体类型。
已知内容写明类型,未知二进制使用合理回退
内容格式明确时,直接指定与正文相符的完整值:
app.get('/download', (req, res) => {
res.type('text/plain');
res.send('hello');
});
如果接口交付的是无法进一步识别的二进制文件,可以使用 application/octet-stream,并保留原来的文件名、下载行为和访问控制。不要为了消除异常头,把所有响应都改成 JSON 或纯文本;类型应跟实际字节及客户端契约一致。
确实需要按扩展名推断时,res.type(extension) 对未知扩展名会回退到 application/octet-stream。这与 res.set('Content-Type', extension) 的行为不同。回退只能表达“通用二进制”,不能保证浏览器按业务预期预览内容。
对自定义格式,应使用其实际约定的完整媒体类型。扩展名来自请求参数时,先做业务允许范围校验,不能把任意输入当作可信响应头值。
在响应离开应用前后各看一次
检查设置类型的调用链,尤其是下载封装和统一响应中间件。可以只记录不含业务内容的类型值及选中的分支,避免为排查响应头而输出文件、令牌或完整响应。
修正后,实际 GET 的 Content-Type 应与内容一致;客户端需要字符集时也应正确。再覆盖一个已知扩展名和一个未知扩展名,确认后者按接口规定回退或被拒绝,不再输出 false。
如果应用内部看到的值正确,公网响应仍然不同,继续检查后面的中间件与反向代理是否覆盖了头。不要把改用 setHeader()、关闭浏览器类型检查或放宽安全响应头当作这条路径的修复。


