请求头生成
按 CORS、缓存、内容协商、认证分组拼出可直接用的响应头。
四组表单(CORS、缓存、内容协商、认证与安全)共 66 个字段,字段名、控件类型与默认值只在一份表里定义一次,未知的分组名回落到 CORS。输出的头部块一行一个头,行首的 # 请求 / # 响应 标出这一行该由谁发出——Origin、Accept 系列、Authorization、Cookie 属于请求侧,Cache-Control、Vary、ETag、Set-Cookie 与全部 *-Policy、*-Security 属于响应侧,把它们混进同一份「请求头配置」是这类生成器的通病,所以注释行是刻意生成的。CORS 组还会额外渲染预检请求本体(浏览器自动发、方法固定 OPTIONS 的 Access-Control-Request-Method 与 Access-Control-Request-Headers),下方附 6 行预检触发条件表;缓存组下方附 Cache-Control 指令语义表。
它做的只有静态拼装与规范校验:不发请求、不测 CORS、不验证书,也不连任何服务器。安全头只在勾选时输出并写明代价:HSTS 的 preload 是单向门,COEP: require-corp 会让所有不带 CORP 也不走 CORS 的跨源子资源加载失败,COOP: same-origin 切断 window.opener 回写,Permissions-Policy 连自己和所有 iframe 一起砍能力。这一组刻意不输出 X-Frame-Options(要限制嵌套请写 CSP 的 frame-ancestors),X-XSS-Protection 与 Expect-CT 只在显式打开「输出已废弃头」时出现,并以错误级说明它们现在唯一的正确取值。
请求头生成怎么用
- 切组填值:顶部四个按钮切 CORS / 缓存 / 内容协商 / 认证与安全,每组下方两列铺开该组的字段:CORS 填两个 Origin 与 Allow-* 列表、凭证和预检开关(开关是真正的 role=switch 按钮);缓存填 max-age、s-maxage、stale-* 与可见性、验证器;内容协商填 Accept 系列、Content-Type 与 charset、Content-Encoding 和分块开关;认证与安全填认证方案、Cookie 与 Set-Cookie 属性、再加一串安全头开关。切走时这组的值留在草稿里,切回来还是你改过的那份。
- 按级别读校验:错误一律只列在顶部横幅:横幅第一行写「当前配置有 N 处语法或语义冲突」并展开讲判据,N>1 时其余错误紧跟其后;表格里不重复错误级别。下方的「校验明细」折叠表只收注意与说明两级——注意是容易被误读的(private 不等于敏感数据、Pragma 的历史包袱),说明是背景与取舍。计数行写「N 行头 · N 个错误 · N 条注意与说明」,折叠区标题另给「0 注意 · 3 说明」这样的分级别拆分。
- 取值方式:头部块是一整块带行号的纯文本,# 开头的行是分侧注释而不是要发的头(计数行会写明几行头、几行注释、共几行),选中后用你自己的方式取走;本页没有复制按钮,也不把表单内容发到任何服务端——所有判定都在你浏览器里的脚本中完成。
- 字段名与 Origin 的判据:校验项都能逐条对上规范。字段名必须是 RFC 9110 允许的 tchar 组合;Origin 得是「协议://主机[:端口]」且不含路径与结尾斜杠;Access-Control-Allow-Origin 只能有一个值,且与 Allow-Credentials: true 互斥(带凭证时 Fetch 规范要求回具体源);Max-Age 取非负整数,并在取 0 时说明各浏览器的预检缓存上限(Chrome/Edge 约 600 秒、Firefox 约 86400 秒,写更大也只按各自上限存);免预检判定按白名单五头、三方法、三个 Content-Type,外加单值 128 字节、CORS-unsafe 字符集、language-range 字符集与「单个字节区间才算」的 Range,合计 256 字节这条写在预检表里。
- 缓存组的指令冲突:缓存组查指令冲突:no-store 压过 max-age/no-cache/must-revalidate/immutable、no-cache 与 immutable 语义相反、immutable 缺长 max-age 等于没写、s-maxage 只对共享缓存生效;ETag 必须是带引号的 opaque-tag(可带 W/ 前缀),Last-Modified 只认 GMT 的 IMF-fixdate,Age 与 max-age 一起算出还剩多少秒新鲜度。
常见问题
为什么 Allow-Origin 不能一次放行多个站点?
这个头的语法只允许一个值(或 *),规范里没有列表形式,浏览器是拿字符串去比对当前请求的 Origin。要多源放行只有两条路:服务端读请求的 Origin,命中白名单就原样回那一个,并给响应加 Vary: Origin(否则缓存会把 A 站的放行结果发给 B 站),或者在前面加一层同源代理。带凭证时更不能写 *:Fetch 规范规定 cookie、Authorization、客户端证书存在时 Allow-Origin 必须是具体源,写了也一律判定失败——这就是本页把 * 加 Allow-Credentials 直接报成错误的原因。
no-cache 和 no-store 差在哪,为什么名字这么容易误解?
no-store 是「谁都不许存」,每次都完整走网络,代价最高,只该给真正敏感的接口用;no-cache 是「可以存,但每次复用前必须回源验证」,配合 ETag 或 Last-Modified 命中 304 时不传 body,所以名字里的 cache 指的是存。max-age 给的是新鲜期,期内直接复用;must-revalidate 管的是过期之后不许再用陈旧副本(含离线);stale-while-revalidate 反过来允许过期后先顶 N 秒再后台更新;immutable 承诺新鲜期内连验证请求都省,但要配长 max-age 才有意义。本页因此把 no-store 加 max-age 报成冲突(其余指令都会被忽略),把 no-cache 加 immutable 报成语义相反。
为什么我在浏览器里设置的头没发出去?
一类是 forbidden header,脚本设了会被静默忽略:压缩协商(Accept-Encoding)、Host/Origin/Referer/User-Agent、Content-Length、Cookie 与连接层字段都在这一类,本页对 Accept-Encoding 会直接在说明里点出来——那一行只在 Node、Python、curl 这类客户端里有效。另一类是触发了预检:只要设置任何白名单外的头(X-Requested-With、Authorization、Content-Type: application/json 都算),或白名单头的值超 128 字节、含 CORS-unsafe 字符,就得先走 OPTIONS,方法在 GET/HEAD/POST 里也不免预检。Cookie 与 User-Agent 你根本改不了,要带凭证请改 fetch 的 credentials 并由服务端回 Allow-Credentials。
内容协商那一组查些什么?
内容协商组自己解析 Accept 列表的 q 值(只认 q,取值 0–1 且最多三位小数),q=0 判为明确拒绝,缺 */* 兜底与「更具体的媒体类型先赢、不看 q」都会提示;Content-Length 与 Transfer-Encoding: chunked 同时出现直接判错,因为 RFC 9110 要求接收端把这种消息按非法处理并关连接,这正是请求走私的入口。
认证与安全组的字段有哪些坑?
认证与安全组把「这一行该不该发」也讲清楚:Basic 走 UTF-8 到 Base64(用户名含冒号判错,因为它是 user:pass 的唯一分隔符),并提醒 Base64 只是编码不是加密;Bearer 的令牌里不许出现空白(b64token 只允许 A-Za-z0-9-._~);Digest 只给字段骨架,因为 response 要先收到带 nonce 的 401 才算得出来。Set-Cookie 按 Path、Domain、SameSite、Secure、HttpOnly、Partitioned、Max-Age、Expires 的顺序拼接,SameSite=None 缺 Secure 判错,Cookie 请求行里出现这些属性名同样判错,不写 Path 时说明浏览器会按「发起 URL 去掉最后一段」推断目录。
对应功能编号 #59无需安装,手机端同样可用按 Ctrl + K 换工具