
📋 文章摘要:
本文详细解析了 Node.js 中 res.setHeader() 与 res.writeHead() 的核心区别与使用场景:
- 本质区别:
setHeader是内存中的准备操作,可多次修改;writeHead是立即发送操作,一旦调用即锁定头部 - 协作顺序:必须先
setHeader后writeHead,反之会报错 - 使用建议:动态头部用
setHeader,固定头部用writeHead,流式响应必须先用writeHead - 核心原则:
setHeader用于"幕后准备",writeHead用于"前台开演"
在 Node.js 原生 http 模块中,res.setHeader() 和 res.writeHead() 都用于设置响应头,但它们的核心本质区别在于:setHeader 是“写在内存里”的准备操作,而 writeHead 是“真正发出去”的发送操作。
你可以把响应头想象成一封即将寄出的信:
res.setHeader():像往信封上贴便签(准备信息),可以随时贴、反复贴,但只要没交给邮局,就还能修改。res.writeHead():像把信封递进邮筒并盖上邮戳(状态码 + 头部),一旦投递,信封内容(头部)就锁死了,无法再更改。
1. 核心区别详解
| 对比维度 | res.setHeader(name, value) | res.writeHead(statusCode[, statusMessage][, headers]) |
|---|---|---|
| 主要职责 | 仅设置/修改单个响应头的值 | 一次性发送状态码和所有响应头(开启响应流) |
| 是否处理状态码 | ❌ 不处理,只关心 Header 字段 | ✅ 必须传入状态码(如 200、404) |
| 调用次数 | 可以多次调用,分别设置不同字段 | 通常只能调用一次(因为调用后头部就发送了) |
| 发送时机(关键) | 只修改内存中的 _headers 对象,不立即发送。头部会在第一次调用 res.write() 或 res.end() 时隐式发送。 | 立即将状态行和头部数据写入网络套接字(显式发送),标志着响应头阶段结束。 |
| 调用后的影响 | 调用后仍可通过再次 setHeader 覆盖同名头部 | 调用后,若再调用 setHeader 会抛出 Error: Cannot set headers after they are sent |
2. 二者的协作顺序(重要场景)
它们并非互斥,经常搭配使用,但顺序决定结果:
-
先
setHeader,后writeHead(推荐):
setHeader设置的头部会暂存在内存中,当调用writeHead时,会将所有已设置的头部(包括之前的)连同状态码一起发送出去。此时writeHead中的headers对象如果与之前同名,会覆盖之前的设置。res.setHeader('Content-Type', 'text/plain'); res.setHeader('X-Custom', 'Hello'); res.writeHead(200, { 'X-Custom': 'World' }); // 最终 X-Custom 为 'World',Content-Type 仍为 'text/plain' -
先
writeHead,后setHeader(报错):
一旦writeHead执行完毕,头部已被发出,此时再调用setHeader会直接触发 Node.js 的ERR_HTTP_HEADERS_SENT错误。
3. 实战选择建议
| 场景 | 推荐做法 |
|---|---|
需要动态添加多个头部(如根据逻辑判断是否加 Cache-Control) | 用 res.setHeader() 逐一设置,最后用 res.writeHead(200) 发送状态码(无头部参数),或直接 res.end() 让头部自动隐式发送。 |
| 需要设置状态码,且头部固定不变(如重定向) | 直接用 res.writeHead(302, { Location: '/new' }) 一步到位,代码最简洁。 |
| 流式传输大文件(需先发完头部再慢慢写 body) | 务必先用 res.writeHead() 显式发送头部,再用 res.write() 分块传输数据,确保客户端提前知晓头部信息。 |
💎 一句话总结
res.setHeader()是“幕后准备”(可多次修改,最后统一发送),而res.writeHead()是“前台开演”(立即发送状态码+头部,一旦开演就谢绝改词)。
日常开发中,如果不需要严格区分发送时机,只用res.setHeader()+res.end()或直接res.writeHead()一步到位均可;但如果涉及流式响应,则必须先用writeHead发送头部,再用write推送数据体。


264

被折叠的 条评论
为什么被折叠?



