跳到主要内容

HTTP 协议

HTTP(Hypertext Transfer Protocol,超文本传输协议)是 Web 的基础协议,定义了客户端和服务器之间传输超文本数据的规则。从简单的网页浏览到复杂的 API 交互,HTTP 无处不在。

HTTP 概述

HTTP 是应用层协议,基于 TCP 协议,默认端口 80。它采用请求-响应模型,客户端发送请求,服务器返回响应。

HTTP 的特点

无状态:每个请求独立处理,服务器不保存客户端状态。优点是简单高效,缺点是无法保持会话状态。通过 Cookie 和 Session 可以实现状态管理。

基于请求-响应:客户端发起请求,服务器返回响应。服务器不能主动向客户端发送数据(WebSocket 可以)。

灵活可扩展:可以传输任意类型的数据,通过 Content-Type 头部指定。

支持持久连接:HTTP/1.1 默认开启持久连接,一个 TCP 连接可以发送多个请求。

HTTP 版本演进

版本年份主要特性
HTTP/0.91991只支持 GET,只能传输 HTML
HTTP/1.01996支持 POST、HEAD,支持多种内容类型
HTTP/1.11997持久连接、分块传输、Host 头部
HTTP/22015多路复用、头部压缩、服务器推送
HTTP/32022基于 QUIC,更快的连接建立

HTTP 请求

请求格式

HTTP 请求由请求行、请求头、空行和请求体组成:

请求行:方法 URL 版本
请求头:头部名: 头部值
空行
请求体:数据

示例

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

{"name": "张三", "age": 25}

请求方法

HTTP 定义了一组请求方法,表示对资源的操作:

方法用途是否有请求体是否幂等
GET获取资源
POST创建资源
PUT更新资源(完整替换)
PATCH更新资源(部分修改)
DELETE删除资源
HEAD获取响应头
OPTIONS查询支持的方法
TRACE回显请求
CONNECT建立隧道

幂等性:多次执行相同请求,结果相同。GET、PUT、DELETE 是幂等的,POST 不是。

GET 与 POST 的区别

特性GETPOST
用途获取数据提交数据
参数位置URL 查询字符串请求体
参数长度受 URL 长度限制无限制
缓存可以被缓存通常不缓存
安全性参数暴露在 URL参数在请求体
幂等性幂等非幂等

请求头

请求头提供请求的附加信息:

通用请求头

头部用途示例
Host目标主机名example.com
User-Agent客户端信息Mozilla/5.0
Accept可接受的响应类型text/html, application/json
Accept-Language可接受的语言zh-CN, en-US
Accept-Encoding可接受的编码方式gzip, deflate
Connection连接管理keep-alive

请求体相关头

头部用途示例
Content-Type请求体类型application/json
Content-Length请求体长度1024
Content-Encoding请求体编码gzip

缓存相关头

头部用途示例
If-Modified-Since条件请求Wed, 21 Oct 2024 07:28:00 GMT
If-None-Match条件请求(ETag)"abc123"
Cache-Control缓存控制no-cache

认证相关头

头部用途示例
Authorization认证信息Bearer token123
Cookie发送 Cookiesession=abc123

请求体

请求体包含要发送的数据,常见格式:

表单数据

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=123456

JSON 数据

POST /api/users HTTP/1.1
Content-Type: application/json

{"name": "张三", "email": "[email protected]"}

文件上传

POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain

文件内容...
------WebKitFormBoundary--

HTTP 响应

响应格式

HTTP 响应由状态行、响应头、空行和响应体组成:

状态行:版本 状态码 原因短语
响应头:头部名: 头部值
空行
响应体:数据

示例

HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 27

{"status": "success"}

状态码

HTTP 状态码表示请求的处理结果,分为五类:

1xx 信息性响应

状态码含义
100 Continue继续发送请求体
101 Switching Protocols协议切换(WebSocket)

2xx 成功

状态码含义
200 OK请求成功
201 Created资源创建成功
204 No Content成功但无响应体
206 Partial Content范围请求成功

3xx 重定向

状态码含义
301 Moved Permanently永久重定向
302 Found临时重定向
304 Not Modified资源未修改(缓存有效)
307 Temporary Redirect临时重定向(保持方法)
308 Permanent Redirect永久重定向(保持方法)

4xx 客户端错误

状态码含义
400 Bad Request请求格式错误
401 Unauthorized未认证
403 Forbidden禁止访问
404 Not Found资源不存在
405 Method Not Allowed方法不允许
408 Request Timeout请求超时
413 Payload Too Large请求体过大
429 Too Many Requests请求过多

5xx 服务器错误

状态码含义
500 Internal Server Error服务器内部错误
501 Not Implemented功能未实现
502 Bad Gateway网关错误
503 Service Unavailable服务不可用
504 Gateway Timeout网关超时

响应头

响应头提供响应的附加信息:

通用响应头

头部用途示例
Server服务器信息nginx/1.18.0
Date响应时间Wed, 21 Oct 2024 07:28:00 GMT
Connection连接管理keep-alive

内容相关头

头部用途示例
Content-Type响应体类型text/html; charset=utf-8
Content-Length响应体长度1024
Content-Encoding响应体编码gzip
Content-Language响应体语言zh-CN

缓存相关头

头部用途示例
Cache-Control缓存控制max-age=3600
ETag资源标识"abc123"
Last-Modified最后修改时间Wed, 21 Oct 2024 07:28:00 GMT
Expires过期时间Wed, 21 Oct 2025 07:28:00 GMT

安全相关头

头部用途示例
Set-Cookie设置 Cookiesession=abc123; HttpOnly
X-Frame-Options防止点击劫持DENY
X-XSS-ProtectionXSS 防护1; mode=block
Content-Security-Policy内容安全策略default-src 'self'

HTTP 缓存

HTTP 缓存可以减少网络传输,提高响应速度。

缓存类型

强缓存:不向服务器发送请求,直接使用本地缓存。

相关头部:

  • Cache-Control: max-age=3600(优先级高)
  • Expires: Wed, 21 Oct 2025 07:28:00 GMT

协商缓存:向服务器验证缓存是否有效,有效则返回 304。

相关头部:

  • Last-Modified / If-Modified-Since
  • ETag / If-None-Match

Cache-Control 指令

指令含义
max-age=秒缓存有效期
no-cache使用前需验证(协商缓存)
no-store不缓存
public可被任何缓存存储
private只能被浏览器缓存
must-revalidate过期后必须验证

缓存流程

请求资源
|
v
检查强缓存 --> 有效 --> 使用缓存
|
无效
|
v
发送请求(带 If-None-Match/If-Modified-Since)
|
v
服务器验证 --> 未修改 --> 304 Not Modified
|
已修改
|
v
200 OK + 新资源

HTTP 持久连接

短连接 vs 长连接

短连接(HTTP/1.0 默认):每个请求建立一个 TCP 连接,请求完成后关闭。开销大,效率低。

长连接(HTTP/1.1 默认):一个 TCP 连接可以发送多个请求。减少连接开销,提高效率。

Connection: keep-alive
Keep-Alive: timeout=5, max=100

队头阻塞

HTTP/1.1 的长连接存在队头阻塞问题:前一个请求未完成时,后续请求必须等待。

解决方案:

  • 使用多个 TCP 连接(浏览器通常限制 6 个)
  • 使用 HTTP/2 的多路复用

HTTP/2

HTTP/2 在不改变 HTTP 语义的前提下,大幅提升性能。

二进制分帧

HTTP/2 将数据分割为更小的帧,以二进制格式传输:

+-----------------------------------------------+
| 帧长度 (24) |
+---------------+---------------+---------------+
| 类型 (8) | 标志 (8) |
+-------------------------------+-------------------------------+
|R| 流标识符 (31) |
+---------------------------------------------------------------+
| 帧载荷 (0...) |
+---------------------------------------------------------------+

多路复用

一个 TCP 连接上可以并行传输多个请求和响应,解决队头阻塞问题。

每个请求/响应是一个流(Stream),流被分割为多个帧,不同流的帧可以交错传输。

头部压缩

HTTP/2 使用 HPACK 算法压缩头部:

  • 使用静态字典编码常见头部
  • 使用动态字典存储自定义头部
  • 使用 Huffman 编码压缩字符串

服务器推送

服务器可以主动向客户端推送资源:

PUSH_PROMISE: /style.css

客户端可以拒绝推送的资源。

HTTP/3

HTTP/3 基于 QUIC 协议,使用 UDP 替代 TCP。

HTTP/3 特点

更快的连接建立:0-RTT 或 1-RTT 建立连接,同时完成 TLS 握手。

解决队头阻塞:QUIC 的多路复用在传输层实现,单个流丢包不影响其他流。

连接迁移:网络切换时不断开连接,使用 Connection ID 标识连接。

内置 TLS 1.3:安全性更高。

HTTP 安全

常见安全问题

中间人攻击:攻击者拦截并篡改通信内容。使用 HTTPS 可以防止。

跨站脚本攻击(XSS):注入恶意脚本。使用 Content-Security-Policy 头部防护。

跨站请求伪造(CSRF):伪造用户请求。使用 CSRF Token 防护。

点击劫持:将页面嵌入恶意网站。使用 X-Frame-Options 头部防护。

安全相关响应头

Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'

HTTP 编程

Python 示例

发送 GET 请求

import requests

response = requests.get('https://api.example.com/users')
print(response.status_code)
print(response.json())

发送 POST 请求

import requests

data = {'name': '张三', 'age': 25}
response = requests.post(
'https://api.example.com/users',
json=data,
headers={'Authorization': 'Bearer token123'}
)
print(response.json())

处理响应头

import requests

response = requests.get('https://example.com')
print(response.headers['Content-Type'])
print(response.headers.get('Set-Cookie'))

使用 http.client

import http.client
import json

conn = http.client.HTTPSConnection('api.example.com')
headers = {'Content-Type': 'application/json'}
data = json.dumps({'name': '张三'})

conn.request('POST', '/users', data, headers)
response = conn.getresponse()

print(response.status)
print(response.read().decode())
conn.close()

HTTP 调试工具

curl

# GET 请求
curl https://api.example.com/users

# POST 请求
curl -X POST -H "Content-Type: application/json" \
-d '{"name":"张三"}' \
https://api.example.com/users

# 查看响应头
curl -i https://example.com

# 携带 Cookie
curl -b "session=abc123" https://example.com

httpie

# GET 请求
http GET https://api.example.com/users

# POST 请求
http POST https://api.example.com/users name=张三 age:=25

# 认证
http -a user:pass GET https://api.example.com/users

浏览器开发者工具

按 F12 打开开发者工具,Network 面板可以查看:

  • 请求和响应头
  • 请求和响应体
  • 请求时间
  • Cookie 信息

小结

HTTP 是 Web 的核心协议:

  1. 请求-响应模型:客户端发送请求,服务器返回响应
  2. 请求方法:GET、POST、PUT、DELETE 等
  3. 状态码:表示请求处理结果
  4. 缓存机制:强缓存和协商缓存
  5. HTTP/2 和 HTTP/3:多路复用、头部压缩、更快连接

理解 HTTP 协议是 Web 开发和 API 设计的基础。

练习

  1. 描述 HTTP 请求和响应的格式
  2. 说明 GET 和 POST 的区别
  3. 解释 HTTP 缓存的工作原理
  4. 比较 HTTP/1.1、HTTP/2 和 HTTP/3 的区别