当你打开浏览器,在地址栏输入一个网址并按下回车,几秒钟后网页就呈现在眼前。这个过程看似简单,背后却是HTTP协议在工作。无论是浏览网页、使用手机App,还是调用后台API,HTTP协议都在默默支撑着互联网的数据传输。理解HTTP,是理解Web世界的起点。

HTTP是什么

HTTP是HyperText Transfer Protocol的缩写,中文译为超文本传输协议。它是一种应用层协议,运行在TCP/IP协议栈之上,用于在Web浏览器和Web服务器之间传输数据。

1989年,Tim Berners-Lee在CERN(欧洲核子研究中心)提出了World Wide Web的概念。为了实现这个构想,他设计了四个核心组件:HTML(超文本标记语言)、HTTP(超文本传输协议)、Web浏览器和Web服务器。1991年8月6日,第一个网站上线,HTTP协议正式登上历史舞台。

HTTP的设计初衷非常简单:让客户端(通常是浏览器)能够从服务器获取文档。最初的HTTP/0.9版本只有一个GET方法,请求只有一行,响应只返回HTML内容,没有状态码,没有头部信息。随着Web的快速发展,HTTP逐渐演进,功能越来越丰富,但核心理念始终不变:客户端发送请求,服务器返回响应

请求-响应模型

HTTP采用请求-响应(Request-Response)模型工作。这个模型可以概括为一句话:客户端发起请求,服务器返回响应

┌─────────┐                      ┌─────────┐
│         │  ──── Request ────▶  │         │
│ Client  │                      │ Server  │
│         │  ◀─── Response ────  │         │
└─────────┘                      └─────────┘

图片来源:基于HTTP协议规范绘制

整个过程是这样的:

  1. 客户端发送请求:用户在浏览器中输入URL或点击链接,浏览器构建HTTP请求消息,通过TCP连接发送给服务器。

  2. 服务器处理请求:服务器收到请求后,解析请求内容,根据请求方法、路径和头部信息决定如何处理。

  3. 服务器返回响应:服务器将处理结果封装成HTTP响应消息,包含状态码、响应头和响应体,发送回客户端。

  4. 客户端处理响应:浏览器收到响应后,根据状态码判断请求是否成功,解析响应体中的内容并渲染页面。

这个模型的一个关键特点是无状态(Stateless)。每次HTTP请求都是独立的,服务器不会"记住"之前的请求。这种设计简化了服务器实现,但也带来了挑战——比如用户登录后如何保持登录状态?解决方案是使用Cookie和Session,在请求中携带状态信息。

HTTP请求消息的结构

一个完整的HTTP请求消息由三部分组成:请求行(Request Line)请求头(Request Headers)请求体(Request Body)

POST /api/users HTTP/1.1          ← 请求行
Host: example.com                 ← 请求头
Content-Type: application/json
Content-Length: 42
User-Agent: Mozilla/5.0
                                  ← 空行
{"name":"张三","email":"[email protected]"}  ← 请求体

请求行

请求行包含三个信息,用空格分隔:

  • 请求方法:如GETPOSTPUTDELETE
  • 请求目标(Request Target):通常是URL的路径部分,如/api/users
  • HTTP版本:如HTTP/1.1

请求头

请求头是键值对形式的关键信息,用于描述请求的元数据。每个头部字段占一行,格式为字段名: 字段值。常见的请求头包括:

头部字段 作用 示例
Host 指定服务器域名和端口 Host: www.example.com
User-Agent 客户端信息 User-Agent: Mozilla/5.0 (Windows NT 10.0)
Accept 可接受的响应内容类型 Accept: text/html,application/json
Accept-Language 可接受的语言 Accept-Language: zh-CN,zh;q=0.9
Accept-Encoding 可接受的编码方式 Accept-Encoding: gzip, deflate
Content-Type 请求体的媒体类型 Content-Type: application/json
Content-Length 请求体的长度(字节) Content-Length: 42
Authorization 认证信息 Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Cookie 携带的Cookie Cookie: session_id=abc123

请求体

请求体包含要发送给服务器的数据。并非所有请求都有请求体——GET请求通常没有请求体,而POSTPUTPATCH请求通常包含请求体。

请求体的格式由Content-Type头部指定,常见格式包括:

  • application/json:JSON格式,API开发中最常用
  • application/x-www-form-urlencoded:表单键值对,键值用=连接,多个键值用&分隔
  • multipart/form-data:多部分表单数据,用于文件上传

HTTP请求方法详解

HTTP定义了一组请求方法(也称为HTTP动词),每个方法表示对资源的不同操作意图。

方法 作用 是否有请求体 是否幂等 是否安全
GET 获取资源
POST 创建资源
PUT 更新资源(完整替换)
PATCH 更新资源(部分修改)
DELETE 删除资源
HEAD 获取资源头部信息
OPTIONS 查询支持的方法

幂等性和安全性

理解这两个概念对于正确使用HTTP方法非常重要:

安全性(Safe):指该方法不会修改服务器上的资源状态。GETHEADOPTIONS是安全方法。安全方法可以被缓存、预取,不会产生副作用。

幂等性(Idempotent):指多次执行相同请求,结果与执行一次相同。GETPUTDELETEHEADOPTIONS是幂等的。POST不是幂等的——两次相同的POST请求可能创建两个相同的资源。

常用方法详解

GET:最常用的方法,用于获取资源。请求参数通常放在URL的查询字符串中:

GET /api/users?page=1&size=10 HTTP/1.1
Host: api.example.com

POST:用于创建新资源或提交数据。数据放在请求体中:

POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"name":"李四","email":"[email protected]"}

PUT:用于完整更新资源。需要提供资源的完整数据:

PUT /api/users/123 HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"name":"王五","email":"[email protected]","age":25}

PATCH:用于部分更新资源。只提供需要修改的字段:

PATCH /api/users/123 HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"age":26}

DELETE:用于删除资源:

DELETE /api/users/123 HTTP/1.1
Host: api.example.com

HTTP响应消息的结构

HTTP响应消息同样由三部分组成:状态行(Status Line)响应头(Response Headers)响应体(Response Body)

HTTP/1.1 200 OK                    ← 状态行
Content-Type: application/json     ← 响应头
Content-Length: 85
Cache-Control: max-age=3600
                                   ← 空行
{"id":123,"name":"张三","email":"[email protected]"}  ← 响应体

状态行

状态行包含三个信息:

  • HTTP版本:如HTTP/1.1
  • 状态码:三位数字,表示请求的处理结果,如200
  • 原因短语:状态码的简短描述,如OK

响应头

响应头同样以键值对形式提供元数据。常见的响应头包括:

头部字段 作用 示例
Content-Type 响应体的媒体类型 Content-Type: text/html; charset=utf-8
Content-Length 响应体的长度 Content-Length: 1024
Content-Encoding 响应体的编码方式 Content-Encoding: gzip
Cache-Control 缓存控制指令 Cache-Control: max-age=3600
Set-Cookie 设置Cookie Set-Cookie: session_id=xyz; HttpOnly; Secure
Location 重定向目标地址 Location: https://example.com/new
Server 服务器信息 Server: nginx/1.18.0

响应体

响应体是服务器返回的实际数据。对于HTML页面,响应体是HTML代码;对于API请求,响应体通常是JSON数据。某些响应(如204 No Content)没有响应体。

HTTP状态码详解

状态码是HTTP协议的重要组成部分,它告诉客户端请求的处理结果。状态码是一个三位数字,第一位数字表示状态码的类别。

状态码分类

类别 范围 含义
1xx 100-199 信息性响应——请求已被接收,正在处理
2xx 200-299 成功——请求已成功接收、理解并接受
3xx 300-399 重定向——需要客户端采取进一步操作
4xx 400-499 客户端错误——请求包含语法错误或无法完成
5xx 500-599 服务器错误——服务器无法完成有效请求

常见状态码详解

成功响应(2xx)

  • 200 OK:请求成功。最常用的成功状态码。
  • 201 Created:创建成功。通常用于POST请求后返回。
  • 204 No Content:成功但无返回内容。常用于DELETE请求。
  • 206 Partial Content:部分内容。用于断点续传或分块下载。

重定向(3xx)

  • 301 Moved Permanently:资源已永久移动到新地址。浏览器会缓存新地址。
  • 302 Found:资源临时移动。常用于临时重定向。
  • 304 Not Modified:资源未修改。配合缓存使用,告诉客户端可以使用缓存的版本。

客户端错误(4xx)

  • 400 Bad Request:请求语法错误。客户端需要修改请求内容。
  • 401 Unauthorized:需要身份认证。需要在请求中携带认证信息。
  • 403 Forbidden:禁止访问。服务器拒绝执行请求。
  • 404 Not Found:资源不存在。最广为人知的状态码。
  • 405 Method Not Allowed:请求方法不被允许。
  • 429 Too Many Requests:请求过于频繁,触发限流。

服务器错误(5xx)

  • 500 Internal Server Error:服务器内部错误。最常见的服务器错误。
  • 502 Bad Gateway:网关错误。代理服务器从上游服务器收到无效响应。
  • 503 Service Unavailable:服务暂时不可用。通常是因为服务器过载或正在维护。
  • 504 Gateway Timeout:网关超时。代理服务器等待上游服务器响应超时。

HTTP与HTTPS

HTTP协议传输的数据是明文的,任何人都可以在网络中截获并查看内容。这在涉及敏感信息(如密码、银行卡号)时非常危险。HTTPS应运而生。

HTTPS是HTTP Secure的缩写,它在HTTP和TCP之间加入了一层TLS/SSL加密协议。简单来说,HTTPS = HTTP + TLS/SSL。

HTTPS的工作原理

HTTPS的核心是TLS握手过程:

  1. 客户端发起连接:客户端发送支持的加密套件列表。
  2. 服务器响应:服务器选择一个加密套件,并发送数字证书。
  3. 证书验证:客户端验证证书的有效性(是否由可信CA签发、是否过期、域名是否匹配)。
  4. 密钥交换:客户端生成会话密钥,用服务器的公钥加密后发送给服务器。
  5. 建立加密通道:双方使用会话密钥进行对称加密通信。

HTTP与HTTPS的对比

对比项 HTTP HTTPS
端口 80 443
数据传输 明文 加密
安全性 不安全,易被窃听和篡改 安全,数据加密传输
证书 不需要 需要数字证书
性能 略快 略慢(TLS握手开销)

现代Web开发中,HTTPS已成为标配。浏览器会对HTTP网站标记"不安全",搜索引擎也会优先收录HTTPS网站。

HTTP缓存机制

缓存是提升Web性能的重要手段。HTTP提供了完善的缓存控制机制,分为强缓存协商缓存两种。

强缓存

强缓存是指浏览器直接使用本地缓存,不向服务器发送请求。通过响应头控制:

  • Expires:指定资源的过期时间(绝对时间)。缺点是依赖客户端时间。
  • Cache-Control: max-age=秒数:指定资源在多少秒内有效。优先级高于Expires
Cache-Control: max-age=3600

这表示资源在3600秒(1小时)内有效,期间浏览器直接使用缓存,不发送请求。

协商缓存

当强缓存失效后,浏览器会向服务器发送请求,验证缓存是否仍然有效。这叫协商缓存。

Last-Modified / If-Modified-Since

服务器在响应中返回Last-Modified头部,表示资源的最后修改时间:

Last-Modified: Wed, 08 Mar 2026 10:00:00 GMT

浏览器下次请求时,携带If-Modified-Since头部:

If-Modified-Since: Wed, 08 Mar 2026 10:00:00 GMT

服务器比较时间:如果资源未修改,返回304 Not Modified(无响应体);如果已修改,返回新内容和200 OK

ETag / If-None-Match

ETag是资源的唯一标识符(通常是内容哈希值),比Last-Modified更精确:

ETag: "abc123"

浏览器下次请求时携带If-None-Match

If-None-Match: "abc123"

服务器比较ETag:匹配则返回304,不匹配则返回新内容。

ETag优先级高于Last-Modified,因为Last-Modified只能精确到秒,且内容不变但修改时间变化时会产生误判。

HTTP协议版本演进

HTTP协议经历了多次重大演进,每个版本都解决了上一版本的问题。

HTTP/0.9(1991年)

最初的版本,极为简单:

  • 只有GET方法
  • 没有请求头和响应头
  • 只能传输HTML
  • 没有状态码

HTTP/1.0(1996年)

增加了重要特性:

  • 引入POSTHEAD方法
  • 引入请求头和响应头
  • 引入状态码
  • 支持Content-Type,可传输任意类型数据
  • 每次请求需要新建TCP连接,完成后关闭

HTTP/1.1(1997年)

最广泛使用的版本,引入了关键改进:

  • 持久连接Connection: keep-alive,一个TCP连接可以传输多个请求
  • 管道化:可以连续发送多个请求,无需等待响应(但实际支持不佳)
  • Host头部:支持虚拟主机,一个IP地址可以托管多个域名
  • 分块传输Transfer-Encoding: chunked,支持动态生成内容
  • 新增PUTDELETEOPTIONS等方法

HTTP/1.1存在队头阻塞问题:即使使用持久连接,请求必须按顺序处理,一个慢请求会阻塞后续请求。

HTTP/2(2015年)

为解决性能问题而设计:

  • 二进制分帧:消息以二进制帧形式传输,更高效
  • 多路复用:一个TCP连接可并行处理多个请求/响应,解决队头阻塞
  • 头部压缩:HPACK算法压缩头部,减少重复传输
  • 服务器推送:服务器可主动推送资源到客户端

HTTP/3(2022年)

基于QUIC协议的最新版本:

  • 基于UDP:放弃TCP,使用QUIC协议(基于UDP实现可靠传输)
  • 解决TCP层队头阻塞:丢包只影响单个流,不会阻塞其他请求
  • 更快的连接建立:0-RTT连接建立,减少握手延迟
  • 内置TLS 1.3:加密成为强制要求

实践建议

理解HTTP协议对日常开发很有帮助:

设计API时:遵循RESTful原则,正确使用HTTP方法和状态码。用GET获取资源,POST创建资源,PUT完整更新,PATCH部分更新,DELETE删除。返回正确的状态码,让客户端能正确处理响应。

处理缓存时:合理设置Cache-ControlETag,减少重复请求,提升性能。静态资源使用强缓存,动态资源使用协商缓存。

处理安全时:始终使用HTTPS。设置安全头部如Content-Security-PolicyX-Frame-OptionsStrict-Transport-Security。Cookie设置HttpOnlySecure属性。

调试时:善用浏览器开发者工具的Network面板,查看请求响应的详细信息。使用curl命令行工具测试API。


参考资料