167 lines
4.6 KiB
Markdown
167 lines
4.6 KiB
Markdown
|
|
---
|
|||
|
|
tags: [计算机网络, HTTP, HTTP/1.1, HTTP/2, HTTP/3, QUIC]
|
|||
|
|
create time: 2026-05-18 02:30
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
# HTTP/1.1 完全指南
|
|||
|
|
|
|||
|
|
## 概述
|
|||
|
|
|
|||
|
|
HTTP (HyperText Transfer Protocol) 是万维网的数据传输协议,从 Mosaic 浏览器的最初需求发展而来,至今仍是互联网上使用最广泛的协议之一。
|
|||
|
|
|
|||
|
|
## HTTP 消息结构
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Request 示例:
|
|||
|
|
POST /api/users HTTP/1.1 ← Request Line
|
|||
|
|
Host: api.example.com ← Headers
|
|||
|
|
Content-Type: application/json ← Header
|
|||
|
|
Content-Length: 42 ← Header
|
|||
|
|
Authorization: Bearer abc123 ← Header
|
|||
|
|
← Blank line separates headers from body
|
|||
|
|
{"name": "Alice", "email": "alice@example.com"} ← Body
|
|||
|
|
|
|||
|
|
Response 示例:
|
|||
|
|
HTTP/1.1 201 Created ← Status Line
|
|||
|
|
Date: Mon, 17 May 2026 02:30:00 GMT ← Headers
|
|||
|
|
Location: https://api.example.com/users/42 ← Header
|
|||
|
|
Content-Type: application/json ← Header
|
|||
|
|
Content-Length: 35 ← Header
|
|||
|
|
|
|||
|
|
{"id": 42, "name": "Alice"} ← Body
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Request Line 格式
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
METHOD SP Request-URI SP HTTP-Version CRLF
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 常用 Method
|
|||
|
|
|
|||
|
|
| Method | 安全(Safe)? | 幂等(Idempotent)? | 含义 |
|
|||
|
|
|--------|-----------|------------------|------|
|
|||
|
|
| GET | ✅ | ✅ | 获取资源 |
|
|||
|
|
| HEAD | ✅ | ✅ | 只获取响应头 |
|
|||
|
|
| POST | ❌ | ❌ | 提交数据创建新资源 |
|
|||
|
|
| PUT | ❌ | ✅ | 替换整个资源 |
|
|||
|
|
| PATCH | ❌ | ❌ | 部分更新资源 |
|
|||
|
|
| DELETE | ❌ | ✅ | 删除资源 |
|
|||
|
|
| OPTIONS | ✅ | ✅ | 查询服务器支持的 Method |
|
|||
|
|
| CONNECT | N/A | N/A | 建立隧道(代理/HTTPS) |
|
|||
|
|
| TRACE | ✅ | ✅ | 回显收到的请求(调试) |
|
|||
|
|
|
|||
|
|
### 常见 Status Code
|
|||
|
|
|
|||
|
|
| 类别 | 含义 | 举例 |
|
|||
|
|
|------|------|------|
|
|||
|
|
| 1xx | 信息性 | 100 Continue, 101 Switching Protocols |
|
|||
|
|
| 2xx | 成功 | 200 OK, 201 Created, 204 No Content |
|
|||
|
|
| 3xx | 重定向 | 301 Moved Permanently, 302 Found, 304 Not Modified |
|
|||
|
|
| 4xx | 客户端错误 | 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests |
|
|||
|
|
| 5xx | 服务端错误 | 500 Internal Server Error, 502 Bad Gateway, 503 Service Unavailable |
|
|||
|
|
|
|||
|
|
## Keep-Alive(持久连接)— HTTP/1.1 默认行为
|
|||
|
|
|
|||
|
|
HTTP/1.1 中 `Connection: keep-alive` 是默认的——一个 TCP 连接可承载多个 HTTP 请求/响应:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
单一 TCP 连接上的多次请求:
|
|||
|
|
|
|||
|
|
TCP Established ✅
|
|||
|
|
|
|||
|
|
Client → Server: GET /page1.html
|
|||
|
|
Server → Client: 200 + HTML
|
|||
|
|
|
|||
|
|
Client → Server: GET /style.css
|
|||
|
|
Server → Client: 200 + CSS
|
|||
|
|
|
|||
|
|
Client → Server: GET /app.js
|
|||
|
|
Server → Client: 200 + JS
|
|||
|
|
|
|||
|
|
Client → Server: Connection: close (或超时自动关闭)
|
|||
|
|
Server → Client: ACK → TCP FIN
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**好处:** 避免每次请求都进行三次握手 (+TLS 四次握手)。
|
|||
|
|
|
|||
|
|
### Pipeline(管道化)— HTTP/1.1 的未启用功能
|
|||
|
|
|
|||
|
|
理论上可以在同一个连接上**不等待前一个响应就发送下一个请求**:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
Client 连续发三个请求:
|
|||
|
|
GET /a ← 不等响应
|
|||
|
|
GET /b
|
|||
|
|
GET /c
|
|||
|
|
|
|||
|
|
Server 必须按顺序返回:
|
|||
|
|
200 /a
|
|||
|
|
200 /b
|
|||
|
|
200 /c
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**为什么几乎没人用?**
|
|||
|
|
- Server 端实现复杂且 Bug 多
|
|||
|
|
- 一旦某个响应阻塞,后续所有响应都被卡住(HoL blocking)
|
|||
|
|
- HTTP/2 的多路复用彻底解决了这个问题
|
|||
|
|
|
|||
|
|
## Chunked Transfer Encoding
|
|||
|
|
|
|||
|
|
当不知道 Content-Length 时(如流式生成内容),使用 chunked 编码:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
HTTP/1.1 200 OK
|
|||
|
|
Transfer-Encoding: chunked
|
|||
|
|
|
|||
|
|
5\r\n\r\nHello\r\n ← 5 bytes of data: "Hello"
|
|||
|
|
7\r\n\r\n World!\r\n ← 7 bytes: " World!"
|
|||
|
|
0\r\n\r\n ← 终止 chunk
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// Go net/http 中自动使用 chunked
|
|||
|
|
w.Header().Set("Transfer-Encoding", "chunked")
|
|||
|
|
w.Write([]byte("part 1"))
|
|||
|
|
w.Write([]byte("part 2"))
|
|||
|
|
w.WriteHeader(200) // WriteHeader 必须在 Write 之后才生效 chunked
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Go 中的 HTTP 客户端实践
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
package main
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"fmt"
|
|||
|
|
"io"
|
|||
|
|
"net/http"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func main() {
|
|||
|
|
client := &http.Client{
|
|||
|
|
Timeout: 10 * time.Second,
|
|||
|
|
Transport: &http.Transport{
|
|||
|
|
MaxIdleConns: 100,
|
|||
|
|
MaxIdleConnsPerHost: 10,
|
|||
|
|
IdleConnTimeout: 90 * time.Second,
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resp, err := client.Get("https://example.com")
|
|||
|
|
if err != nil {
|
|||
|
|
panic(err)
|
|||
|
|
}
|
|||
|
|
defer resp.Body.Close()
|
|||
|
|
|
|||
|
|
io.Copy(os.Stdout, resp.Body)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 关联笔记
|
|||
|
|
|
|||
|
|
- [[hhs/NETWORK/HTTP/2多路复用]] — HTTP/2 如何解决 HTTP/1.1 的问题
|
|||
|
|
- [[hhs/NETWORK/HTTP/3与QUIC]] — 基于 UDP 的下一代 HTTP
|
|||
|
|
- [[hhs/NETWORK/TCP三次握手与四次挥手]] — HTTP 依赖的底层 TCP 连接
|