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.9 | 1991 | 只支持 GET,只能传输 HTML |
| HTTP/1.0 | 1996 | 支持 POST、HEAD,支持多种内容类型 |
| HTTP/1.1 | 1997 | 持久连接、分块传输、Host 头部 |
| HTTP/2 | 2015 | 多路复用、头部压缩、服务器推送 |
| HTTP/3 | 2022 | 基于 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 的区别:
| 特性 | GET | POST |
|---|---|---|
| 用途 | 获取数据 | 提交数据 |
| 参数位置 | 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 | 发送 Cookie | session=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 | 设置 Cookie | session=abc123; HttpOnly |
| X-Frame-Options | 防止点击劫持 | DENY |
| X-XSS-Protection | XSS 防护 | 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-SinceETag/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 的核心协议:
- 请求-响应模型:客户端发送请求,服务器返回响应
- 请求方法:GET、POST、PUT、DELETE 等
- 状态码:表示请求处理结果
- 缓存机制:强缓存和协商缓存
- HTTP/2 和 HTTP/3:多路复用、头部压缩、更快连接
理解 HTTP 协议是 Web 开发和 API 设计的基础。
练习
- 描述 HTTP 请求和响应的格式
- 说明 GET 和 POST 的区别
- 解释 HTTP 缓存的工作原理
- 比较 HTTP/1.1、HTTP/2 和 HTTP/3 的区别