3.1.1 HTTP 协议基础 #
HTTP(HyperText Transfer Protocol)是互联网上应用最广泛的网络协议之一。作为一个应用层协议,HTTP 定义了客户端和服务器之间如何进行通信。深入理解 HTTP 协议是进行 Web 开发的基础,本节将详细介绍 HTTP 协议的核心概念和工作机制。
HTTP 协议概述 #
协议特点 #
HTTP 协议具有以下主要特点:
- 无状态性:每个请求都是独立的,服务器不会保留之前请求的信息
- 请求-响应模型:客户端发送请求,服务器返回响应
- 基于 TCP:HTTP 建立在可靠的 TCP 连接之上
- 文本协议:HTTP 消息使用人类可读的文本格式
- 可扩展性:通过头部字段可以轻松扩展功能
协议版本 #
HTTP 协议经历了多个版本的演进:
- HTTP/0.9(1991 年):最初版本,只支持 GET 方法
- HTTP/1.0(1996 年):引入了头部字段、状态码、多种请求方法
- HTTP/1.1(1997 年):持久连接、分块传输、缓存控制
- HTTP/2(2015 年):二进制协议、多路复用、服务器推送
- HTTP/3(2022 年):基于 QUIC 协议,进一步提升性能
HTTP 消息结构 #
请求消息结构 #
HTTP 请求消息由以下部分组成:
请求行
请求头部
空行
请求体(可选)
请求行 #
请求行包含三个部分:
方法 URI HTTP版本
示例:
GET /api/users HTTP/1.1
POST /api/users HTTP/1.1
PUT /api/users/123 HTTP/1.1
请求头部 #
请求头部包含多个键值对,提供请求的附加信息:
Host: example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
完整请求示例 #
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 45
Authorization: Bearer token123
{"name": "张三", "email": "[email protected]"}
响应消息结构 #
HTTP 响应消息结构如下:
状态行
响应头部
空行
响应体(可选)
状态行 #
状态行包含 HTTP 版本、状态码和状态描述:
HTTP版本 状态码 状态描述
示例:
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found
HTTP/1.1 500 Internal Server Error
完整响应示例 #
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 78
Date: Mon, 23 Oct 2023 10:30:00 GMT
{"id": 123, "name": "张三", "email": "[email protected]", "created_at": "2023-10-23T10:30:00Z"}
HTTP 请求方法 #
HTTP 定义了多种请求方法,每种方法都有特定的语义:
GET 方法 #
用于获取资源,是最常用的方法:
GET /api/users HTTP/1.1
Host: api.example.com
特点:
- 安全的(不会修改服务器状态)
- 幂等的(多次执行结果相同)
- 可缓存
- 参数通过 URL 查询字符串传递
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]"}
特点:
- 不安全
- 幂等的
- 通常用于完整更新资源
DELETE 方法 #
用于删除资源:
DELETE /api/users/123 HTTP/1.1
Host: api.example.com
特点:
- 不安全
- 幂等的
- 用于删除指定资源
PATCH 方法 #
用于部分更新资源:
PATCH /api/users/123 HTTP/1.1
Host: api.example.com
Content-Type: application/json
{"email": "[email protected]"}
HEAD 方法 #
类似 GET,但只返回头部信息:
HEAD /api/users/123 HTTP/1.1
Host: api.example.com
OPTIONS 方法 #
用于获取服务器支持的方法:
OPTIONS /api/users HTTP/1.1
Host: api.example.com
HTTP 状态码 #
HTTP 状态码用于表示请求的处理结果,分为五个类别:
1xx 信息性状态码 #
- 100 Continue:客户端应继续发送请求
- 101 Switching Protocols:服务器正在切换协议
2xx 成功状态码 #
- 200 OK:请求成功
- 201 Created:资源创建成功
- 202 Accepted:请求已接受,但尚未处理
- 204 No 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:方法不允许
- 409 Conflict:请求冲突
- 422 Unprocessable Entity:请求格式正确但语义错误
5xx 服务器错误状态码 #
- 500 Internal Server Error:服务器内部错误
- 501 Not Implemented:功能未实现
- 502 Bad Gateway:网关错误
- 503 Service Unavailable:服务不可用
- 504 Gateway Timeout:网关超时
HTTP 头部字段 #
HTTP 头部字段提供了请求和响应的元数据信息。
通用头部字段 #
这些字段可以出现在请求和响应中:
Date: Mon, 23 Oct 2023 10:30:00 GMT
Connection: keep-alive
Cache-Control: no-cache
Transfer-Encoding: chunked
请求头部字段 #
客户端发送的头部字段:
Host: api.example.com
User-Agent: Go-http-client/1.1
Accept: application/json, text/plain
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Cookie: session_id=abc123; user_pref=dark_mode
If-Modified-Since: Mon, 23 Oct 2023 09:00:00 GMT
If-None-Match: "686897696a7c876b7e"
响应头部字段 #
服务器返回的头部字段:
Server: nginx/1.18.0
Content-Type: application/json; charset=utf-8
Content-Length: 1234
Content-Encoding: gzip
Set-Cookie: session_id=xyz789; Path=/; HttpOnly; Secure
Location: /api/users/124
ETag: "686897696a7c876b7e"
Last-Modified: Mon, 23 Oct 2023 10:30:00 GMT
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
实体头部字段 #
描述消息体的字段:
Content-Type: application/json; charset=utf-8
Content-Length: 1234
Content-Encoding: gzip
Content-Language: zh-CN
Content-Range: bytes 200-1023/1024
内容协商 #
HTTP 支持内容协商,允许客户端和服务器协商最适合的内容格式。
Accept 系列头部 #
客户端使用 Accept 系列头部表明偏好:
Accept: application/json, application/xml;q=0.9, text/plain;q=0.8
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Charset: utf-8, iso-8859-1;q=0.5
质量值(q 值) #
q 值表示偏好程度,范围从 0 到 1:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
服务器响应 #
服务器根据客户端偏好返回合适的内容:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Language: zh-CN
Content-Encoding: gzip
Vary: Accept, Accept-Language, Accept-Encoding
缓存机制 #
HTTP 缓存机制可以显著提升性能和用户体验。
缓存控制头部 #
Cache-Control: public, max-age=3600
Cache-Control: private, no-cache
Cache-Control: no-store
Expires: Mon, 23 Oct 2023 11:30:00 GMT
条件请求 #
客户端可以发送条件请求来验证缓存:
If-Modified-Since: Mon, 23 Oct 2023 09:00:00 GMT
If-None-Match: "686897696a7c876b7e"
服务器响应:
HTTP/1.1 304 Not Modified
ETag: "686897696a7c876b7e"
Cache-Control: public, max-age=3600
持久连接 #
HTTP/1.1 默认使用持久连接,可以在同一个 TCP 连接上发送多个请求。
Connection 头部 #
Connection: keep-alive
Connection: close
Keep-Alive 头部 #
Keep-Alive: timeout=5, max=100
分块传输编码 #
当内容长度未知时,可以使用分块传输编码:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: text/plain
7\r\n
Mozilla\r\n
9\r\n
Developer\r\n
7\r\n
Network\r\n
0\r\n
\r\n
HTTPS 和安全性 #
HTTPS 是 HTTP 的安全版本,使用 TLS/SSL 加密:
TLS 握手过程 #
- 客户端发送 Client Hello
- 服务器发送 Server Hello 和证书
- 客户端验证证书
- 密钥交换和加密建立
- 开始加密通信
安全头部 #
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
HTTP/2 特性 #
HTTP/2 引入了多项性能改进:
二进制协议 #
HTTP/2 使用二进制格式而非文本格式,提高了解析效率。
多路复用 #
在单个连接上可以并行发送多个请求和响应:
// HTTP/1.1 需要多个连接
conn1 -> GET /api/users
conn2 -> GET /api/posts
conn3 -> GET /api/comments
// HTTP/2 可以在单个连接上复用
conn -> GET /api/users (stream 1)
-> GET /api/posts (stream 3)
-> GET /api/comments (stream 5)
服务器推送 #
服务器可以主动推送资源给客户端:
PUSH_PROMISE frame:
:method: GET
:path: /style.css
:scheme: https
:authority: example.com
头部压缩 #
使用 HPACK 算法压缩头部,减少传输开销。
实际应用示例 #
让我们通过一个完整的 HTTP 交互示例来理解协议的工作流程:
用户注册流程 #
- 客户端发送注册请求:
POST /api/register HTTP/1.1
Host: api.example.com
Content-Type: application/json
Content-Length: 67
User-Agent: MyApp/1.0
{"username": "zhangsan", "email": "[email protected]", "password": "secret123"}
- 服务器处理并响应:
HTTP/1.1 201 Created
Content-Type: application/json
Content-Length: 156
Location: /api/users/12345
Set-Cookie: session_id=abc123xyz; Path=/; HttpOnly; Secure; SameSite=Strict
Date: Mon, 23 Oct 2023 10:30:00 GMT
{"id": 12345, "username": "zhangsan", "email": "[email protected]", "created_at": "2023-10-23T10:30:00Z"}
- 客户端获取用户信息:
GET /api/users/12345 HTTP/1.1
Host: api.example.com
Cookie: session_id=abc123xyz
Accept: application/json
If-None-Match: "v1.0"
- 服务器返回用户信息:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 156
ETag: "v1.0"
Cache-Control: private, max-age=300
Last-Modified: Mon, 23 Oct 2023 10:30:00 GMT
{"id": 12345, "username": "zhangsan", "email": "[email protected]", "created_at": "2023-10-23T10:30:00Z"}
最佳实践 #
1. 正确使用 HTTP 方法 #
GET /api/users # 获取用户列表
POST /api/users # 创建新用户
GET /api/users/123 # 获取特定用户
PUT /api/users/123 # 完整更新用户
PATCH /api/users/123 # 部分更新用户
DELETE /api/users/123 # 删除用户
2. 合理设置状态码 #
// 成功创建资源
w.WriteHeader(http.StatusCreated) // 201
// 资源未找到
w.WriteHeader(http.StatusNotFound) // 404
// 请求参数错误
w.WriteHeader(http.StatusBadRequest) // 400
// 服务器内部错误
w.WriteHeader(http.StatusInternalServerError) // 500
3. 设置适当的头部 #
Content-Type: application/json; charset=utf-8
Cache-Control: public, max-age=3600
ETag: "version-1.0"
Last-Modified: Mon, 23 Oct 2023 10:30:00 GMT
4. 实现内容协商 #
accept := r.Header.Get("Accept")
switch {
case strings.Contains(accept, "application/json"):
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data)
case strings.Contains(accept, "application/xml"):
w.Header().Set("Content-Type", "application/xml")
xml.NewEncoder(w).Encode(data)
default:
w.Header().Set("Content-Type", "text/plain")
fmt.Fprint(w, data)
}
小结 #
HTTP 协议是 Web 开发的基础,理解其工作原理对于构建高质量的 Web 应用至关重要。本节介绍了:
- 协议特点:无状态、请求-响应模型、基于 TCP
- 消息结构:请求行/状态行、头部、消息体
- 请求方法:GET、POST、PUT、DELETE 等的语义和用法
- 状态码:1xx-5xx 各类状态码的含义
- 头部字段:通用、请求、响应、实体头部的作用
- 高级特性:内容协商、缓存、持久连接、HTTP/2
掌握这些基础知识将为后续学习 Go HTTP 编程奠定坚实的基础。在下一节中,我们将深入学习 Go 语言的 net/http
包,了解如何在实际开发中应用这些 HTTP 协议知识。