为什么 Header 是 HTTP 的灵魂

为什么 Header 是 HTTP 的灵魂

前言

上一篇文章里,我们从整体上认识了 HTTP:

text 复制代码
HTTP 是浏览器和服务器之间传输资源的应用层协议。

一个 HTTP 请求和响应,大致可以拆成:

text 复制代码
请求:请求行 + 请求头 + 请求体
响应:状态行 + 响应头 + 响应体

如果只看请求行、状态行和响应体,我们大概能知道:

text 复制代码
请求了哪个接口;
请求是否成功;
服务端返回了什么数据。

但真正让 HTTP 变得强大的,往往不是这些最基础的部分,而是 Header。

比如你在项目里遇到的很多问题,最后都会回到请求头或响应头:

  • 为什么用户登录后,刷新页面还是登录状态?
  • 为什么请求里会带 Cookie
  • 为什么请求头里要放 Authorization
  • 为什么接口明明返回了 200,浏览器却提示 CORS 错误?
  • 为什么有些资源返回 304?
  • 为什么 JS、CSS 能被长期缓存?
  • 为什么接口返回 JSON,浏览器知道它是 JSON?
  • 为什么响应内容可以被 gzip 或 Brotli 压缩?

这些问题背后,几乎都离不开 Header。

所以这一篇,我们不急着深入 Token、Cookie、缓存、跨域,而是先把 Header 这个入口讲清楚。

你可以先记住一句话:

text 复制代码
Header 是 HTTP 的扩展层。

HTTP 的很多高级能力,都是通过 Header 实现的。

一、Header 是什么

Header,中文通常叫"头部"。

它是一组键值对,用来描述 HTTP 请求或响应的附加信息。

一个请求头可能长这样:

http 复制代码
GET /api/user/current HTTP/1.1
Host: example.com
Accept: application/json
Authorization: Bearer xxx
Cookie: sessionId=abc123

其中:

http 复制代码
Host: example.com
Accept: application/json
Authorization: Bearer xxx
Cookie: sessionId=abc123

这些就是请求头。

一个响应头可能长这样:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache
Set-Cookie: sessionId=abc123; HttpOnly; Secure
Access-Control-Allow-Origin: https://front.example.com

其中:

http 复制代码
Content-Type: application/json
Cache-Control: no-cache
Set-Cookie: sessionId=abc123; HttpOnly; Secure
Access-Control-Allow-Origin: https://front.example.com

这些就是响应头。

Header 的格式一般是:

http 复制代码
字段名: 字段值

比如:

http 复制代码
Content-Type: application/json

表示:

text 复制代码
当前请求体或响应体的数据格式是 JSON。

二、为什么说 Header 是 HTTP 的灵魂

因为 HTTP 的基础结构很简单。

请求行只能表达:

text 复制代码
用什么方法,访问哪个路径,使用哪个 HTTP 版本。

例如:

http 复制代码
GET /api/user HTTP/1.1

状态行只能表达:

text 复制代码
HTTP 层面请求结果是什么。

例如:

http 复制代码
HTTP/1.1 200 OK

请求体和响应体主要承载具体数据。

例如:

json 复制代码
{
  "code": 0,
  "data": {
    "name": "Alice"
  }
}

但问题是,真实 Web 通信远远不止这些。

浏览器和服务器还需要沟通很多额外信息:

text 复制代码
这次请求来自哪个站点?
用户有没有登录?
请求体是什么格式?
响应体是什么格式?
资源能不能缓存?
缓存多久?
资源有没有变化?
内容有没有被压缩?
服务器要不要给浏览器设置 Cookie?
跨域请求能不能被前端读取?
页面允许加载哪些脚本?

这些信息放在哪里?

答案就是 Header。

所以 Header 像是 HTTP 的"能力扩展区"。

如果没有 Header,HTTP 只能完成最朴素的请求和响应。

有了 Header,HTTP 才能支持:

  • 内容协商
  • 数据格式说明
  • 压缩传输
  • 缓存控制
  • 登录态维护
  • Token 鉴权
  • Cookie 设置
  • CORS 跨域
  • 安全策略
  • 文件上传下载
  • 连接管理

这就是为什么可以说:

text 复制代码
Header 是 HTTP 的灵魂。

三、请求头和响应头有什么区别

Header 可以分为两类:

text 复制代码
请求头 Request Headers
响应头 Response Headers

1. 请求头

请求头是客户端发给服务器的附加信息。

它在告诉服务器:

text 复制代码
我是谁;
我想要什么;
我能接收什么;
我发给你的数据是什么格式;
我有没有携带身份凭证;
这个请求来自哪里。

比如:

http 复制代码
GET /api/user/current HTTP/1.1
Host: example.com
Accept: application/json
Authorization: Bearer xxx
Cookie: sessionId=abc123
Origin: https://front.example.com

这里每个请求头都有自己的含义:

请求头 作用
Host 告诉服务器要访问哪个主机
Accept 告诉服务器客户端希望接收什么格式
Authorization 携带认证信息,常见是 token
Cookie 携带浏览器保存的 Cookie
Origin 表示跨域请求来自哪个源

2. 响应头

响应头是服务器返回给客户端的附加信息。

它在告诉浏览器:

text 复制代码
我返回的数据是什么格式;
这个资源能不能缓存;
我要不要给你设置 Cookie;
这个跨域请求允不允许;
响应内容有没有压缩;
页面有哪些安全限制。

比如:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=3600
Set-Cookie: sessionId=abc123; HttpOnly
Access-Control-Allow-Origin: https://front.example.com
Content-Encoding: br

这些响应头分别表示:

响应头 作用
Content-Type 告诉浏览器响应体是什么格式
Cache-Control 告诉浏览器怎么缓存资源
Set-Cookie 让浏览器保存 Cookie
Access-Control-Allow-Origin 告诉浏览器是否允许跨域读取
Content-Encoding 告诉浏览器响应体使用了什么压缩方式

简单记:

text 复制代码
请求头:客户端告诉服务端一些信息。
响应头:服务端告诉客户端一些信息。

四、Header 解决的第一个问题:内容是什么

HTTP 传输的内容可能有很多类型。

比如:

  • HTML
  • CSS
  • JavaScript
  • JSON
  • 图片
  • 字体
  • 文件流

浏览器需要知道:

text 复制代码
服务端返回的这一坨内容,到底应该怎么解析?

这就需要 Content-Type

1. Content-Type

Content-Type 用来表示请求体或响应体的媒体类型。

响应里常见:

http 复制代码
Content-Type: text/html; charset=utf-8

表示响应体是 HTML。

http 复制代码
Content-Type: application/json

表示响应体是 JSON。

http 复制代码
Content-Type: text/css

表示响应体是 CSS。

http 复制代码
Content-Type: image/png

表示响应体是 PNG 图片。

前端接口里最常见的是:

http 复制代码
Content-Type: application/json

当后端返回:

http 复制代码
Content-Type: application/json

{
  "code": 0,
  "data": {
    "id": 1
  }
}

浏览器或请求库就知道:

text 复制代码
这个响应体应该按 JSON 处理。

2. 请求里的 Content-Type

Content-Type 不只可以出现在响应头,也可以出现在请求头。

比如前端提交 JSON:

http 复制代码
POST /api/login HTTP/1.1
Content-Type: application/json

{
  "username": "alice",
  "password": "123456"
}

它在告诉后端:

text 复制代码
我发给你的请求体是 JSON。

如果提交表单:

http 复制代码
Content-Type: application/x-www-form-urlencoded

username=alice&password=123456

如果上传文件:

http 复制代码
Content-Type: multipart/form-data

注意,使用 FormData 上传文件时,一般不要手动设置 Content-Type

js 复制代码
const formData = new FormData()
formData.append('file', file)

fetch('/api/upload', {
  method: 'POST',
  body: formData
})

因为浏览器会自动生成 multipart/form-data 需要的 boundary。

3. Accept

Accept 是请求头,表示客户端希望接收什么类型的数据。

例如:

http 复制代码
Accept: application/json

意思是:

text 复制代码
我希望你最好返回 JSON。

AcceptContent-Type 的区别可以这样记:

text 复制代码
Accept:我想要什么。
Content-Type:我给你的是什么。

例如:

http 复制代码
Accept: application/json
Content-Type: application/json

可以理解为:

text 复制代码
我希望收到 JSON;
我现在发给你的请求体也是 JSON。

五、Header 解决的第二个问题:能不能压缩

前端性能优化里,经常会提到:

text 复制代码
开启 gzip 或 Brotli 压缩。

这个能力也依赖 Header。

浏览器请求时会告诉服务器:

http 复制代码
Accept-Encoding: gzip, deflate, br

意思是:

text 复制代码
我支持 gzip、deflate、br 这些压缩格式。

服务器如果决定使用 Brotli 压缩响应,会返回:

http 复制代码
Content-Encoding: br

意思是:

text 复制代码
响应体已经用 br 压缩过了。

浏览器收到后,会先解压,再交给页面使用。

压缩适合:

  • HTML
  • CSS
  • JavaScript
  • JSON
  • SVG

不太适合:

  • JPEG
  • PNG
  • MP4
  • ZIP

因为这些格式本身通常已经压缩过,再压缩收益不大。

这一部分你可以先建立一个印象:

text 复制代码
HTTP 压缩不是浏览器和服务器心照不宣完成的。
而是客户端通过 Accept-Encoding 表示自己支持什么,服务端通过 Content-Encoding 表示实际用了什么。

六、Header 解决的第三个问题:用户是谁

HTTP 本身是无状态的。

也就是说,HTTP 协议本身不会记住:

text 复制代码
上一次请求是谁发的;
这个用户是否登录过;
这次请求和上一次请求有没有关系。

所以登录态需要额外机制。

而这些机制,也离不开 Header。

Cookie 是浏览器保存的一小段数据。

服务端可以通过响应头设置 Cookie:

http 复制代码
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure

浏览器保存后,后续请求符合条件时,会自动带上:

http 复制代码
Cookie: sessionId=abc123

流程是:

text 复制代码
用户登录
-> 服务端校验成功
-> 服务端通过 Set-Cookie 返回 sessionId
-> 浏览器保存 Cookie
-> 后续请求浏览器自动带上 Cookie
-> 服务端根据 Cookie 识别用户

这里有两个 Header:

text 复制代码
Set-Cookie:响应头,服务端让浏览器保存 Cookie。
Cookie:请求头,浏览器把 Cookie 带回服务端。

所以 Cookie 不是前端代码每次手写到请求头里的。

很多时候它是浏览器自动管理的。

2. Authorization

另一种常见鉴权方式是 token。

登录成功后,后端可能把 token 放在响应体里返回:

json 复制代码
{
  "code": 0,
  "data": {
    "token": "xxx.yyy.zzz"
  },
  "message": "success"
}

前端拿到 token 后保存起来。

后续请求时,前端主动加请求头:

http 复制代码
Authorization: Bearer xxx.yyy.zzz

例如:

js 复制代码
fetch('/api/user/current', {
  headers: {
    Authorization: `Bearer ${token}`
  }
})

所以:

text 复制代码
Cookie 通常是浏览器自动带;
Authorization 通常是前端代码主动加。

它们都可以用于身份识别,只是机制不同。

这一块后续可以单独写一篇:

text 复制代码
Cookie、Session、Token:HTTP 无状态下如何保持登录态。

七、Header 解决的第四个问题:资源能不能缓存

浏览器缓存也是通过 Header 控制的。

比如服务端返回一个 JS 文件:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/javascript
Cache-Control: max-age=31536000

console.log('hello')

这里的:

http 复制代码
Cache-Control: max-age=31536000

表示:

text 复制代码
这个资源在一段时间内可以直接使用缓存。

这就是强缓存相关的 Header。

如果是协商缓存,可能会看到:

http 复制代码
ETag: "abc123"
Last-Modified: Thu, 10 Sep 2026 08:00:00 GMT

浏览器下次请求时可能带上:

http 复制代码
If-None-Match: "abc123"
If-Modified-Since: Thu, 10 Sep 2026 08:00:00 GMT

服务端判断资源没变,就返回:

http 复制代码
HTTP/1.1 304 Not Modified

这里又出现了一组 Header:

Header 类型 作用
Cache-Control 响应头 控制缓存策略
ETag 响应头 资源标识
Last-Modified 响应头 资源最后修改时间
If-None-Match 请求头 携带上次收到的 ETag
If-Modified-Since 请求头 携带上次收到的修改时间

所以缓存问题本质上也是:

text 复制代码
浏览器和服务器通过 Header 协商资源是否还能继续使用。

后续缓存文章里,我们会详细讲:

  • 强缓存
  • 协商缓存
  • 304
  • ETag
  • Last-Modified
  • 为什么静态资源要带 hash
  • 为什么 HTML 不适合长缓存

八、Header 解决的第五个问题:跨域能不能读取

跨域问题是前端最常见的网络问题之一。

很多同学第一次看到 CORS 报错时,会以为:

text 复制代码
请求没有发出去。

但实际要分情况。

对于简单请求,浏览器通常会先把真实请求发出去,并自动带上:

http 复制代码
Origin: https://front.example.com

这个请求头的意思是:

text 复制代码
这次请求来自 https://front.example.com。

服务端如果允许这个来源访问,就返回:

http 复制代码
Access-Control-Allow-Origin: https://front.example.com

浏览器收到响应后,会检查这个响应头。

如果允许,前端 JS 可以读取响应。

如果不允许,浏览器会拦截前端读取响应。

也就是说:

text 复制代码
Origin 是请求头;
Access-Control-Allow-Origin 是响应头;
浏览器根据这些 Header 判断跨域响应能不能交给前端 JS。

如果是非简单请求,比如:

js 复制代码
fetch('https://api.example.com/user', {
  method: 'DELETE',
  headers: {
    Authorization: 'Bearer xxx',
    'Content-Type': 'application/json'
  }
})

浏览器会先发 OPTIONS 预检请求:

http 复制代码
OPTIONS /user HTTP/1.1
Origin: https://front.example.com
Access-Control-Request-Method: DELETE
Access-Control-Request-Headers: authorization, content-type

服务端需要返回:

http 复制代码
Access-Control-Allow-Origin: https://front.example.com
Access-Control-Allow-Methods: GET, POST, DELETE
Access-Control-Allow-Headers: Authorization, Content-Type

预检通过后,浏览器才会发送真正请求。

所以跨域也不是一个神秘的浏览器问题。

它本质上也是:

text 复制代码
浏览器、前端页面、服务器之间通过 Header 建立访问许可。

这一块后续可以单独写一篇:

text 复制代码
CORS 跨域:为什么请求发出去了,但前端拿不到响应。

九、Header 解决的第六个问题:连接怎么管理

在 HTTP/1.1 里,长连接也是通过 Header 表达的。

比如:

http 复制代码
Connection: keep-alive

表示:

text 复制代码
这个 TCP 连接可以暂时不关闭,后续请求继续复用。

HTTP/1.0 时代,默认更偏短连接。

一次请求可能经历:

text 复制代码
建立 TCP 连接
-> 发送请求
-> 接收响应
-> 关闭连接

HTTP/1.1 默认支持长连接,多个请求可以复用同一个 TCP 连接,从而减少连接建立和关闭的成本。

不过到了 HTTP/2,连接管理方式又发生变化。

HTTP/2 通过多路复用,让多个请求和响应在一个 TCP 连接中以 stream 的形式并发传输。

这一部分不需要在 Header 文章里展开太深,只要先知道:

text 复制代码
HTTP 的连接复用、版本演进,也和请求头、响应头的能力扩展有关。

十、常见 Header 速览

为了建立整体感觉,我们可以先看一张表。

常见请求头

请求头 作用
Host 请求目标主机
Accept 客户端希望接收的数据类型
Accept-Encoding 客户端支持的压缩格式
Accept-Language 客户端偏好的语言
Content-Type 请求体的数据类型
Authorization 携带 token 等认证信息
Cookie 携带浏览器保存的 Cookie
Origin 表示跨域请求来源
Referer 表示请求来源页面
If-None-Match 协商缓存,携带 ETag
If-Modified-Since 协商缓存,携带最后修改时间

常见响应头

响应头 作用
Content-Type 响应体的数据类型
Content-Length 响应体长度
Content-Encoding 响应体压缩方式
Cache-Control 缓存控制
Expires 资源过期时间
ETag 资源标识,用于协商缓存
Last-Modified 资源最后修改时间
Set-Cookie 服务端设置 Cookie
Location 重定向地址
Access-Control-Allow-Origin CORS 允许的来源
Access-Control-Allow-Headers CORS 允许的请求头
Access-Control-Allow-Methods CORS 允许的请求方法
Content-Security-Policy 内容安全策略
Strict-Transport-Security 强制 HTTPS 访问策略

这张表不需要一口气全部背下来。

更好的方式是按场景记:

text 复制代码
内容格式:Content-Type、Accept
压缩传输:Accept-Encoding、Content-Encoding
登录鉴权:Cookie、Set-Cookie、Authorization
缓存:Cache-Control、ETag、Last-Modified、If-None-Match、If-Modified-Since
跨域:Origin、Access-Control-Allow-Origin、Access-Control-Allow-Headers
安全:Content-Security-Policy、Strict-Transport-Security

这样就不会觉得 Header 是一堆零散字段。

十一、一个完整例子串起来

假设用户已经登录,前端请求当前用户信息。

前端页面地址是:

text 复制代码
https://front.example.com

接口地址是:

text 复制代码
https://api.example.com/user/current

请求可能是:

http 复制代码
GET /user/current HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer xxx.yyy.zzz
Origin: https://front.example.com
If-None-Match: "user-current-v1"

这个请求里包含了很多信息:

text 复制代码
Accept 表示希望接收 JSON;
Authorization 表示携带 token;
Origin 表示请求来源,用于 CORS;
If-None-Match 表示询问缓存资源是否变化。

服务端可能返回:

http 复制代码
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache
ETag: "user-current-v2"
Access-Control-Allow-Origin: https://front.example.com

{
  "code": 0,
  "data": {
    "id": 1,
    "name": "Alice"
  },
  "message": "success"
}

响应头也在表达很多信息:

text 复制代码
Content-Type 表示响应体是 JSON;
Cache-Control 表示使用缓存前要先验证;
ETag 表示当前资源版本;
Access-Control-Allow-Origin 表示允许这个前端来源读取响应。

你会发现,一个简单的接口请求,背后已经涉及:

  • 数据格式
  • token 鉴权
  • 跨域
  • 缓存
  • 响应体结构

而这些能力的入口,几乎都在 Header 里。

十二、前端调试时怎么看 Header

平时排查网络问题,最常用的是 Chrome DevTools。

打开方式:

text 复制代码
F12
-> Network
-> 点击某个请求
-> Headers

你一般会看到几块:

text 复制代码
General
Response Headers
Request Headers
Payload
Preview / Response

常见排查思路:

1. 接口返回数据格式不对

看:

text 复制代码
Response Headers 里的 Content-Type

比如服务端是否返回了:

http 复制代码
Content-Type: application/json

2. 登录态没带上

看:

text 复制代码
Request Headers 里有没有 Cookie;
Request Headers 里有没有 Authorization;
Application 面板里有没有对应 Cookie 或 localStorage token。

3. 跨域失败

看:

text 复制代码
Request Headers 里的 Origin;
Response Headers 里的 Access-Control-Allow-Origin;
预检请求 OPTIONS 是否成功;
Access-Control-Allow-Headers 是否包含 Authorization、Content-Type 等字段。

4. 缓存没生效

看:

text 复制代码
Response Headers 里的 Cache-Control、ETag、Last-Modified;
Request Headers 里的 If-None-Match、If-Modified-Since;
Status Code 是否是 200、304;
Size 是否显示 from memory cache 或 from disk cache。

所以学 Header 不是为了背名词。

它会直接提升你调试接口、定位问题、看懂 Network 面板的能力。

十三、不要把 Header 当成纯前端或纯后端问题

Header 是前后端共同约定的一部分。

前端会设置一些请求头:

js 复制代码
fetch('/api/user', {
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json'
  }
})

后端会读取这些请求头:

text 复制代码
读取 Authorization,校验 token;
读取 Cookie,找到 session;
读取 Origin,判断是否允许跨域;
读取 If-None-Match,判断缓存是否命中。

后端也会设置响应头:

text 复制代码
Set-Cookie
Cache-Control
ETag
Access-Control-Allow-Origin
Content-Type

浏览器再根据这些响应头决定:

text 复制代码
怎么解析响应;
要不要保存 Cookie;
能不能把跨域响应交给 JS;
资源能不能使用缓存;
要不要解压响应体;
要不要执行安全策略。

所以 Header 不是某一端的事情。

它是:

text 复制代码
浏览器、前端代码、服务端之间的通信约定。

十四、本篇小结

这一篇我们主要讲了为什么 Header 是 HTTP 的灵魂。

可以总结成几句话:

text 复制代码
Header 是 HTTP 的扩展层。
请求头是客户端告诉服务端的附加信息。
响应头是服务端告诉客户端的附加信息。
HTTP 的很多核心能力都通过 Header 实现。

Header 解决的问题包括:

  • 内容是什么:Content-TypeAccept
  • 能不能压缩:Accept-EncodingContent-Encoding
  • 用户是谁:CookieSet-CookieAuthorization
  • 能不能缓存:Cache-ControlETagLast-Modified
  • 跨域能不能读取:OriginAccess-Control-Allow-Origin
  • 页面是否安全:Content-Security-PolicyStrict-Transport-Security

如果只看请求行和响应体,HTTP 像是一个简单的问答协议。

但加上 Header 后,HTTP 才能支撑现代 Web 里的缓存、鉴权、跨域、压缩、安全和性能优化。

所以可以这样理解:

text 复制代码
请求行和状态行决定一次 HTTP 通信的基本动作;
请求体和响应体承载具体数据;
Header 决定这次通信的规则、上下文和扩展能力。
相关推荐
特立独行的猫A1 小时前
AtomMQTT Broker — 用 Rust 实现的轻量级高性能 MQTT 消息代理
前端·后端·架构
IMPYLH1 小时前
HTML 的 <s> 元素
前端·html
lhldsg1 小时前
折扣卡CPS小程序定制全流程实战指南:从需求分析到上线部署
java·前端·小程序
计算机魔术师1 小时前
Lambert 算了一笔账:CUDA 绑定开源生态,每年值 100 亿美元
前端
晴天161 小时前
HTML iframe 标签全面解析:原理、属性、实战场景与最佳实践
前端·html·状态模式
parade岁月1 小时前
倒反天罡!押注 React Native 6 年后,Shopify 又回到了原生开发
android·前端·ios
柚稚姐姐1 小时前
npm install pnpm -g npm error code EACCES npm error syscall symlink
前端·npm·node.js
涛涛ing2 小时前
2026 年,你可以从项目中删掉这 5 个 npm 包了
前端