HTTP头部字段基础:请求头与响应头结构、常见字段分类、自定义字段规范

说起HTTP头部,我第一个想到的就是那句老话——“协议是明文,内容靠自己”。HTTP的头部字段,说白了就是客户端和服务器之间传递的“信封”。信封上写什么,决定了对方怎么理解你。不管是HTTPS水印嵌入还是安全扫描,底层都在和这些字段打交道。

我个人习惯把HTTP头部当成“元数据走廊”。你发一个请求,服务器能通过头部知道你的浏览器、语言偏好、是否缓存,甚至能通过自定义字段传递额外的令牌或水印参数。嗯,今天这节课,咱们就把这个“走廊”的结构、分类和自定义规范彻底理清楚。

请求头与响应头:结构差异

HTTP头部字段分两头:请求头(Request Headers) 和 响应头(Response Headers)。结构上其实一模一样——都是“键: 值”对,每行一个,用CRLF(回车换行)隔开。但用途完全不同。

头部类型 发送者 典型字段 我在项目中遇到过的坑
请求头 客户端(浏览器、APP、脚本) Host, User-Agent, Accept, Cookie, Authorization 有次客户端发请求时漏了Host头,服务器直接啃了半天没认出域名
响应头 服务器 Content-Type, Set-Cookie, Cache-Control, Server, WWW-Authenticate Content-Type写错成text/plain,浏览器不肯渲染HTML页面
通用头
(可在两端出现)
双方 Date, Connection, Via, Cache-Control Cache-Control在两边都能设,优先级逻辑经常搞混
实体头 描述消息体 Content-Length, Content-Encoding, Last-Modified Content-Length算错,导致接收端卡在“等待更多数据”里

请求头的结构示例:

GET /api/watermark HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: application/json
Authorization: Bearer xxxxxx

响应头的结构示例:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Set-Cookie: sessionid=abc123; Secure; HttpOnly
Cache-Control: no-cache
X-Watermark-Version: 2

你想想看,头部顺序其实不重要,但字段名不区分大小写,这在我刚学的时候吃过亏——我写了个content-type,但服务器只认Content-Type?其实不,HTTP标准说大小写无所谓,但许多框架内部会规范化。我曾经在调试日志里看到大小写不一致,排查了半天才发现是两个团队用的库不一样。

常见字段分类:四大家族

我把头部字段画成四大家族,这样记起来更快:

  1. 通用头(General Headers)——发给谁都行,不关心具体资源。
    典型:Date、Connection、Cache-Control、Via、Upgrade。
  2. 请求头(Request Headers)——只从客户端到服务器。
    典型:Host、User-Agent、Accept、Referer、Authorization、Cookie。
  3. 响应头(Response Headers)——只从服务器到客户端。
    典型:Server、Set-Cookie、WWW-Authenticate、Access-Control-Allow-Origin。
  4. 实体头(Entity Headers)——描述消息体的元信息。
    典型:Content-Type、Content-Length、Content-Encoding、Last-Modified、ETag。
一个小提醒:如果你在写HTTPS水印系统,重点关注X-*自定义字段和Content-Type——水印参数经常被塞进实体头或自定义请求头里。我做过一个案例,水印字段写在X-Watermark-Payload里,但因为Content-Type没设对,代理直接把这个自定义头给吞了。嗯,疼过一回就记住了。

自定义字段规范:从X-到正式注册

自定义字段,就是你自己取名的头部字段。比如我习惯用X-Request-ID做链路追踪,用X-Watermark-传递水印参数。

早期的惯例是加X-前缀,表示非标准、实验性的字段。但RFC 6648(2012年)已经废弃了这个要求——因为X-前缀会导致标准化困难,而且内部使用的字段也可能被其他系统误判。现在的建议是什么?

  • 不强制X-前缀,但建议内部使用:如果你只在内部系统或边缘节点传递水印,用X-Watermark-Version完全没问题,只要能保证不冲突。
  • 正式注册的字段不带X-:如果你想把字段推向标准化,需要遵循RFC 3864,字段名要描述行为而不是加前缀。例如Watermark-Version、Watermark-Payload。
  • 大小写与连字符:标准推荐首字母大写并用连字符(X-Watermark-Expires),当然实际解析时大小写不敏感。我在项目里统一用小写+连字符(x-watermark-expires),团队内保持风格一致就好。
避坑指南:我曾经碰到过一个中间代理(比如CDN或者反向代理),它们默认会过滤掉X-开头的头部字段,除非你显式配置白名单。如果你的水印字段依赖自定义头通过代理,一定要检查代理的策略,否则字段会消失得无声无息。

本章核心逻辑图谱

为了帮你一眼看清HTTP头部字段的整体结构,我画了一张分层架构图。它展示了请求头、响应头、通用头、实体头四大家族的位置关系,以及自定义字段的位置和约束。

HTTP头部字段架构 请求头 (Request Headers) 典型字段:Host, User-Agent, Accept Authorization, Cookie, Referer 自定义:X-Watermark- 方向:客户端 → 服务器 响应头 (Response Headers) 典型字段:Set-Cookie, Server Access-Control-Allow-Origin 自定义:X-Watermark-Version 方向:服务器 → 客户端 通用头 (General Headers) Date, Connection, Cache-Control Via, Upgrade 实体头 (Entity Headers) Content-Type, Content-Length Content-Encoding, ETag 自定义字段(X-前缀 vs 非前缀) RFC 6648:不强制X-前缀,建议内部使用X-,标准化字段不用X- 请求头 响应头 通用头 实体头 自定义字段

这个图我画的是典型的四层结构:请求头在左侧,响应头在右侧,通用头和实体头在下方,自定义字段在这四类中都可以出现——但需要注意标准化和代理兼容性问题。

我在项目中常见的自定义字段陷阱

  • 代理吞噬X-头——有些反代(如Nginx默认配置)会上报X-Real-IP,但也会丢弃其他未知的X-*头。记住:要显式配置proxy_set_header。
  • 多值拼接问题——如果同一个字段名出现多次,有的客户端取第一个值,有的取最后一个,有的取逗号拼接。我在一个项目中用X-Watermark传递了两次值,结果服务器只收到了最后一次,差点以为水印丢了。
  • 超长字段截断——HTTP头部总大小有限制(通常是8KB),如果水印字段里塞了太长的Base64编码,可能直接被截断。建议水印参数用压缩+短编码。

总结一句话

HTTP头部字段就是你的“信息容器”。请求头、响应头、通用头、实体头各司其职,自定义字段给了你最大灵活性,但也带来了兼容性风险。做HTTPS水印时,我建议先搞清楚你的代理链、服务框架和API网关的头部处理策略,再决定字段名字和值格式——否则水印字段被吞了,你都不知道去哪找。