headers的guard属性是浏览器内置的访问控制策略,决定headers实例的可写性:new headers()时为none(可读写),request中为request,no-cors模式下为request-no-cors,response中为response或immutable。

Headers 的 guard 属性是决定你能否修改某个请求或响应头的关键机制。它不是报错提示,而是浏览器内置的“访问控制策略”——一旦 Headers 实例被赋予某种 guard 值,它的可写性就被硬性锁定,无法绕过。
guard 是如何被自动设置的?
你通常不会手动设置 guard,它由创建 Headers 的上下文自动决定:
- 用
new Headers()创建:guard 默认为none,完全可读写 - 在
new Request(url, { headers })中传入 headers:guard 设为request - 使用
mode: 'no-cors'发起请求:headers 的 guard 变为request-no-cors - 从
Response实例获取response.headers:guard 通常是response或immutable
为什么 set('Content-Length') 会报错?
因为这类头部属于浏览器严格管控的“禁止篡改项”。当 guard 是 request 或 response 时,以下头部被列为只读:
-
Content-Length(长度由 body 自动计算) -
Host(由目标 URL 推导) -
Origin(由页面协议/域名/端口自动生成) -
Referer(由导航上下文决定) -
Sec-Fetch-*系列(安全元数据,浏览器专属)
试图修改它们会直接抛出 TypeError: Failed to execute 'set' on 'Headers': Invalid name 或类似错误,不是语法问题,而是 guard 拦截了操作。
request-no-cors 场景下的限制更隐蔽
当你用 fetch(url, { mode: 'no-cors' }) 时,Headers 的 guard 被设为 request-no-cors。此时不仅标准头不可改,连自定义头如 X-App-Token 都会被静默过滤——set() 调用看似成功,但最终发出的请求里根本不会出现该字段。
这是浏览器为防止跨域污染而做的强制约束:no-cors 请求只能发送“CORS 安全列表头”,其余一律丢弃。
如何判断当前 Headers 的 guard 类型?
遗憾的是,Headers 对象没有公开的 .guard 属性供 JS 读取。但你可以通过行为反推:
- 能自由
set/delete所有键 → 很可能是none - 对
Content-Type可设,但对Content-Length报错 → 大概率是request - 任何
set都不生效(尤其自定义头),且 fetch 返回type: "opaque"→ 极可能处于request-no-cors模式
真正可靠的判断方式,是回溯这个 Headers 实例的来源:它是 new 出来的?来自 Request?还是 Response?上下文决定了它的守卫等级。










