HTTP 协议深度解析(二):方法、状态码与 Header 详解
一、HTTP 方法详解
1.1 方法的作用
HTTP 方法(Method)也叫 HTTP 动词(Verb),用于告诉服务器客户端想要执行什么操作。
常见方法:
| 方法 | 含义 | 常用程度 |
|---|---|---|
| GET | 获取资源 | ⭐⭐⭐⭐⭐ |
| POST | 提交数据 | ⭐⭐⭐⭐⭐ |
| HEAD | 获取响应头 | ⭐⭐ |
| PUT | 更新资源 | ⭐⭐ |
| DELETE | 删除资源 | ⭐⭐ |
| OPTIONS | 查询支持的方法 | ⭐ |
| TRACE | 回显请求 | ⭐ |
| CONNECT | 建立隧道 | ⭐ |
最常用的是GET 和 POST,占据了 99% 以上的 HTTP 请求。
1.2 GET 方法(重点)
用途:请求获取指定资源。
请求格式:
GET /index.html HTTP/1.1
Host: www.example.com
特点:
- 参数在 URL 中(查询字符串)
- 浏览器会缓存 GET 请求
- 可以被收藏为书签
- 参数长度有限制(浏览器限制,通常 2KB-8KB)
- 参数会显示在浏览器地址栏,不安全
示例:
GET /search?keyword=Linux&page=2 HTTP/1.1
Host: www.example.com
服务器解析出:
- keyword = "Linux"
- page = "2"
1.2.1 GET 请求的应用场景
- 浏览网页:访问网站首页、文章页面等
- 搜索:搜索引擎查询
- API 查询:获取用户信息、商品列表等
- 图片/CSS/JS 加载:浏览器加载静态资源
示例 URL:
http://www.baidu.com/s?wd=Linux # 百度搜索
http://www.example.com/api/users?id=123 # API 查询
http://www.example.com/images/logo.png # 加载图片
1.3 POST 方法(重点)
用途:向服务器提交数据。
请求格式:
POST /api/login HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
username=admin&password=123
特点:
- 参数在 Body 中(不在 URL 中)
- 浏览器一般不缓存 POST 请求
- 不能被收藏为书签
- 参数长度理论上无限制(实际受服务器限制)
- 参数不显示在地址栏,相对安全
- 可以传输大量数据(文件上传等)
1.3.1 POST 请求的应用场景
- 表单提交:登录、注册、评论等
- 文件上传:上传图片、视频等
- API 操作:创建用户、修改数据等
- 数据提交:提交订单、发送消息等
示例:
POST /api/register HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
username=zhangsan&password=123456&[email protected]
1.4 GET vs POST(面试常考)
| 对比项 | GET | POST |
|---|---|---|
| 参数位置 | URL 查询字符串 | Body 中 |
| 参数长度 | 有限制(2KB-8KB) | 理论无限制 |
| 安全性 | 参数暴露在 URL | 相对安全 |
| 缓存 | 会被缓存 | 一般不会被缓存 |
| 书签 | 可以收藏 | 不能收藏 |
| 后退/刷新 | 无影响 | 数据会重新提交 |
| 语义 | 获取资源 | 提交数据 |
| 幂等性 | 幂等(多次请求结果相同) | 非幂等 |
幂等性的例子:
GET /api/users?id=123 # 多次请求,返回同样的用户信息(幂等)
POST /api/orders # 多次请求,会创建多个订单(非幂等)
重要误区:
- GET 也可以有 Body,POST 也可以有查询参数,但不推荐
- "GET 不安全,POST 安全"是错的,都是明文传输(除非用 HTTPS)
- GET 的参数长度限制是浏览器限制,不是 HTTP 协议限制
1.5 HEAD 方法
用途:获取响应头,不返回 Body。
请求格式:
HEAD /index.html HTTP/1.1
Host: www.example.com
响应:
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
Last-Modified: Wed, 21 Oct 2023 07:20:00 GMT
# (没有 Body)
1.5.1 HEAD 的应用场景
- 检查资源是否存在:不下载内容,只看状态码
- 获取资源元信息:文件大小、修改时间等
- 检查资源是否更新:通过 Last-Modified 判断
curl 测试:
# HEAD 请求
curl --head http://www.baidu.com
# 输出(只有响应头,没有 Body)
HTTP/1.1 200 OK
Server: bfe/1.0.8.18
Date: Wed, 21 Oct 2023 07:28:00 GMT
Content-Type: text/html
Content-Length: 2381
...
1.6 PUT 方法
用途:更新资源。
请求格式:
PUT /api/users/123 HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: 45
{"name":"张三","age":30,"city":"北京"}
特点:
- 用于更新已存在的资源
- 如果资源不存在,可能创建新资源(取决于服务器实现)
- RESTful API 常用
PUT vs POST:
- PUT 是幂等的(多次更新,结果相同)
- POST 是非幂等的(多次提交,可能创建多个资源)
POST:向集合资源创建子资源(服务器分配 URI)
PUT:对指定 URI 的资源整体替换/创建(客户端知道 URI)
1.7 DELETE 方法
用途:删除资源。
请求格式:
DELETE /api/users/123 HTTP/1.1
Host: www.example.com
特点:
- 删除指定资源
- RESTful API 常用
- 幂等(多次删除同一个资源,结果相同)
1.8 OPTIONS 方法
用途:查询服务器支持哪些 HTTP 方法。
请求格式:
OPTIONS /api/users HTTP/1.1
Host: www.example.com
响应:
HTTP/1.1 200 OK
Allow: GET, POST, PUT, DELETE, OPTIONS
Content-Length: 0
应用场景:
- CORS 跨域请求的预检(Preflight),预检请求一般是:OPTIONS + Origin + Access-Control-Request-Method/Headers,响应要带:Access-Control-Allow-Origin/Methods/Headers
- 检查 API 支持哪些操作
curl 测试:
curl -X OPTIONS http://127.0.0.1/
# 如果服务器不支持 OPTIONS
HTTP/1.1 405 Not Allowed
Content-Type: text/html
Content-Length: 166
<html><head><title>405 Not Allowed</title></head><body><center><h1>405 Not Allowed</h1></center></body></html>
二、HTML 表单与 HTTP 的关系
2.1 什么是 HTML 表单
HTML 表单(Form)是网页中收集用户输入的主要方式。
基本结构:
<form action="/api/login" method="POST">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<button type="submit">登录</button>
</form>
关键属性:
action:表单提交的 URLmethod:HTTP 方法(GET 或 POST)
2.2 GET 表单
<form action="/search" method="GET">
<input type="text" name="keyword" placeholder="搜索关键词">
<input type="number" name="page" value="1">
<button type="submit">搜索</button>
</form>
用户输入"Linux",点击提交,浏览器发送:
GET /search?keyword=Linux&page=1 HTTP/1.1
Host: www.example.com
特点:参数拼接到 URL 后面。
2.3 POST 表单
<form action="/api/login" method="POST">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<button type="submit">登录</button>
</form>
用户输入用户名"admin",密码"123",点击提交,浏览器发送:
POST /api/login HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
username=admin&password=123
特点:参数在 Body 中,格式是 key1=value1&key2=value2。
2.4 Content-Type 详解
POST 表单的 Content-Type 有多种:
2.4.1 application/x-www-form-urlencoded(默认)
格式:键值对,&分隔,和 URL 查询参数相同。
Content-Type: application/x-www-form-urlencoded
username=admin&password=123&email=test%40qq.com
特殊字符需要 urlencode(如@变成%40)。
2.4.2 multipart/form-data(文件上传)
用途:上传文件。
<form action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="avatar">
<button type="submit">上传</button>
</form>
请求:
POST /upload HTTP/1.1
Host: www.example.com
Content-Type: multipart/form-data;boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 234
------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data;name="avatar";filename="photo.jpg"
Content-Type: image/jpeg
(二进制图片数据)
------WebKitFormBoundary7MA4YWxkTrZu0gW--
boundary是分隔符,每个字段用 boundary 分隔。
2.4.3 application/json
用途:提交 JSON 数据(现代 Web API 常用)。
fetch('/api/login',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify({username:'admin',password:'123'})
});
请求:
POST /api/login HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: 45
{"username":"admin","password":"123"}
三、HTTP 状态码详解
3.1 状态码分类
HTTP 状态码是三位数字,表示请求的处理结果。
| 分类 | 范围 | 含义 |
|---|---|---|
| 1xx | 100-199 | 信息性状态码(请求正在处理) |
| 2xx | 200-299 | 成功状态码(请求成功) |
| 3xx | 300-399 | 重定向状态码(需要进一步操作) |
| 4xx | 400-499 | 客户端错误状态码 |
| 5xx | 500-599 | 服务器错误状态码 |
3.2 1xx 信息性状态码
| 状态码 | 含义 | 应用场景 |
|---|---|---|
| 100 Continue | 继续 | 上传大文件时,服务器告诉客户端可以继续上传 |
100 Continue 的使用:
客户端先发送请求头:
POST /upload HTTP/1.1
Host: www.example.com
Content-Length: 104857600
Expect: 100-continue
服务器返回:
HTTP/1.1 100 Continue
客户端继续发送 Body(100MB 的文件数据)
避免客户端发送大量数据后才发现服务器不接受请求。
3.3 2xx 成功状态码
| 状态码 | 含义 | 应用场景 |
|---|---|---|
| 200 OK | 成功 | 访问网页、API 查询成功 |
| 201 Created | 已创建 | POST 创建资源成功 |
| 204 No Content | 无内容 | DELETE 成功,不返回内容 |
3.3.1 200 OK
最常见的状态码,表示请求成功。
HTTP/1.1 200 OK
Content-Type: text/html
Content-Length: 1024
<html>...</html>
3.3.2 201 Created
表示资源创建成功。
POST /api/articles HTTP/1.1
Content-Type: application/json
{"title":"新文章","content":"内容"}
响应:
HTTP/1.1 201 Created
Location: /api/articles/123
Content-Type: application/json
{"id":123,"title":"新文章","content":"内容"}
Location 字段指示新资源的 URL。
3.3.3 204 No Content
表示成功,但没有返回内容。
DELETE /api/articles/123 HTTP/1.1
响应:
HTTP/1.1 204 No Content
Content-Length: 0
3.4 3xx 重定向状态码
| 状态码 | 含义 | 是否永久 | 应用场景 |
|---|---|---|---|
| 301 Moved Permanently | 永久重定向 | 是 | 网站换域名 |
| 302 Found | 临时重定向 | 否 | 登录后跳转 |
| 304 Not Modified | 未修改 | - | 浏览器缓存 |
| 307 Temporary Redirect | 临时重定向 | 否 | 保持 HTTP 方法 |
| 308 Permanent Redirect | 永久重定向 | 是 | 保持 HTTP 方法 |
3.4.1 301 永久重定向
表示资源已永久移动到新位置。
GET /old-page HTTP/1.1
Host: www.example.com
响应:
HTTP/1.1 301 Moved Permanently
Location: http://www.example.com/new-page
Content-Length: 0
浏览器行为:
- 收到 301 响应
- 自动跳转到 Location 指定的 URL
- 搜索引擎会更新索引(旧 URL 权重转移到新 URL)
应用场景:
- 网站换域名:
http://old.com → http://new.com - HTTP 升级 HTTPS:
http://example.com → https://example.com
3.4.2 302 临时重定向
表示资源临时移动到新位置。
GET /login HTTP/1.1
Host: www.example.com
响应:
HTTP/1.1 302 Found
Location: http://www.example.com/dashboard
Content-Length: 0
浏览器行为:
- 收到 302 响应
- 自动跳转到 Location 指定的 URL
- 搜索引擎不更新索引(保留原 URL)
应用场景:
- 登录成功后跳转到首页
- 访问需要权限的页面时跳转到登录页
301:通常被当作永久迁移,搜索引擎更倾向转移权重
302:通常被当作临时迁移,搜索引擎更倾向保留原地址(但会根据长期行为调整)
3.4.3 304 未修改
表示资源未修改,使用缓存版本。
GET /style.css HTTP/1.1
Host: www.example.com
If-Modified-Since: Wed, 21 Oct 2023 07:20:00 GMT
响应:
HTTP/1.1 304 Not Modified
Last-Modified: Wed, 21 Oct 2023 07:20:00 GMT
Content-Length: 0
浏览器行为:
- 发送 If-Modified-Since(上次缓存的修改时间)
- 服务器检查资源是否修改
- 未修改,返回 304,浏览器使用缓存
- 已修改,返回 200 和新内容
优势:节省带宽,提高性能。
3.5 4xx 客户端错误状态码
| 状态码 | 含义 | 应用场景 |
|---|---|---|
| 400 Bad Request | 请求错误 | 参数格式错误 |
| 401 Unauthorized | 未认证 | 未登录或 token 过期 |
| 403 Forbidden | 禁止访问 | 没有权限 |
| 404 Not Found | 未找到 | 资源不存在 |
3.5.1 /api/login HTTP/1.1
POST /api/login HTTP/1.1
Host: www.example.com
Content-Type: application/json
Content-Length: ...
{invalid json}
3.5.2 401 Unauthorized
需要认证(登录)。
GET /api/profile HTTP/1.1
响应:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer
{"error":"Authentication required"}
3.5.3 403 Forbidden
没有权限访问。
GET /admin/users HTTP/1.1
Authorization: Bearer <user_token>
响应:
HTTP/1.1 403 Forbidden
{"error":"Admin access required"}
401 vs 403:
- 401:未登录,提供认证后可能访问
- 403:已登录,但权限不足,提供认证也无法访问
3.5.4 404 Not Found
资源不存在。
GET /nonexistent-page HTTP/1.1
响应:
HTTP/1.1 404 Not Found
Content-Type: text/html
<html><body><h1>404 Not Found</h1></body></html>
3.6 5xx 服务器错误状态码
| 状态码 | 含义 | 应用场景 |
|---|---|---|
| 500 Internal Server Error | 服务器内部错误 | 代码异常、崩溃 |
| 502 Bad Gateway | 网关错误 | 代理服务器无法连接上游服务器 |
| 503 Service Unavailable | 服务不可用 | 服务器维护或过载 |
| 504 Gateway Timeout | 网关超时 | 上游服务器响应超时 |
3.6.1 500 Internal Server Error
服务器内部错误(代码 bug、数据库错误等)。
GET /api/users HTTP/1.1
响应:
HTTP/1.1 500 Internal Server Error
Content-Type: text/html
<html><body><h1>500 Internal Server Error</h1></body></html>
3.6.2 502 Bad Gateway
代理服务器无法从上游服务器获取有效响应。
架构:浏览器 → Nginx(代理) → 应用服务器
如果应用服务器挂了,Nginx 返回:
HTTP/1.1 502 Bad Gateway
3.6.3 503 Service Unavailable
服务暂时不可用(维护、过载等)。
HTTP/1.1 503 Service Unavailable
Retry-After: 3600
Content-Type: text/plain
Content-Length: 19
Service Unavailable
四、重定向原理深度剖析
4.1 重定向的工作流程
- 客户端请求 GET /old-page
- 服务器返回 301 + Location: /new-page
- 客户端自动请求 GET /new-page
- 服务器返回 200 + 页面内容(或 JSON 等响应体)。
4.2 Location 字段
Location 字段指定重定向的目标 URL。
可以是相对路径或绝对路径:
# 相对路径
Location: /new-page
# 绝对路径
Location: http://www.example.com/new-page
# 不同域名
Location: http://www.newdomain.com/page
4.3 301 vs 302 的区别
| 对比项 | 301 | 302 |
|---|---|---|
| 含义 | 永久重定向 | 临时重定向 |
| 搜索引擎 | 更新索引,权重转移 | 保留原 URL 索引 |
| 浏览器缓存 | 可能缓存重定向 | 不缓存 |
| 应用场景 | 网站换域名、HTTP→HTTPS | 登录跳转、临时维护页面 |
例子:
网站换域名(用 301):
访问 http://old.com
返回:
HTTP/1.1 301 Moved Permanently
Location: http://new.com
浏览器自动跳转到 http://new.com
搜索引擎更新索引,old.com 的权重转移到 new.com
登录跳转(用 302):
访问 http://example.com/dashboard(需要登录)
返回:
HTTP/1.1 302 Found
Location: http://example.com/login
浏览器自动跳转到登录页
登录成功后,再跳转回 dashboard
4.4 验证重定向
修改我们的 HTTP 服务器,添加重定向功能:
if(strstr(request,"GET /redirect")!=NULL){
const char* response = "HTTP/1.1 302 Found\r\n"
"Location: http://www.baidu.com\r\n"
"Content-Length: 0\r\n"
"\r\n";
write(clientfd, response,strlen(response));
} else {
// 正常处理
}
浏览器访问 http://127.0.0.1:9090/redirect,会自动跳转到百度首页。
五、常见 Header 详解
5.1 Content-Type
用途:指定 Body 的媒体类型(MIME 类型)。
常见值:
| Content-Type | 含义 | 应用场景 |
|---|---|---|
| text/html | HTML 页面 | 网页 |
| text/plain | 纯文本 | txt 文件 |
| application/json | JSON 数据 | API 响应 |
| application/x-www-form-urlencoded | 表单数据 | 表单提交 |
| multipart/form-data | 多部分数据 | 文件上传 |
| image/jpeg | JPEG 图片 | 图片资源 |
| image/png | PNG 图片 | 图片资源 |
| application/pdf | PDF 文档 | PDF 文件 |
示例:
响应 HTML:Content-Type: text/html;charset=utf-8
响应 JSON:Content-Type: application/json
响应图片:Content-Type: image/png
5.2 Content-Length
用途:指定 Body 的字节长度。
Content-Length: 1024
重要性:
- 接收方知道要读取多少字节
- 如果没有 Content-Length,需要用其他方式判断 Body 结束(如 Connection: close)
5.3 Host
用途:指定请求的主机名和端口。
Host: www.example.com:8080
为什么需要 Host:
- 一个 IP 地址可能部署多个网站(虚拟主机)
- 服务器根据 Host 字段判断访问哪个网站
示例:
同一台服务器(IP: 192.168.1.100)部署了三个网站:
- www.site1.com
- www.site2.com
- www.site3.com
请求 GET / HTTP/1.1 Host: www.site1.com → 返回 site1 的首页
请求 GET / HTTP/1.1 Host: www.site2.com → 返回 site2 的首页
5.4 User-Agent
用途:标识客户端的软件环境(浏览器类型、操作系统等)。
示例:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
拆解:
Windows NT 10.0:Windows 10 操作系统Win64; x64:64 位系统Chrome/91.0.4472.124:Chrome 浏览器版本 91
应用场景:
- 服务器根据 User-Agent 返回不同内容(PC 版/移动版)
- 统计访客使用的浏览器和操作系统
5.5 User-Agent 的历史故事
为什么 User-Agent 这么复杂?
早期浏览器市场竞争激烈,为了兼容性,后来的浏览器会在 User-Agent 中加入"Mozilla"、"KHTML"、"Gecko"等字符串,假装自己是其他浏览器,以便网站正常工作。
1993 年 Mosaic 浏览器:User-Agent: NCSA_Mosaic/2.0
1994 年 Netscape Navigator(代号 Mozilla):User-Agent: Mozilla/1.0
1995 年 IE 浏览器(为了兼容,加入 Mozilla):User-Agent: Mozilla/2.0 (compatible; MSIE 3.0)
2003 年 Safari 浏览器(基于 KHTML 引擎):User-Agent: Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/124 (KHTML, like Gecko) Safari/125
现在的 Chrome:User-Agent: Mozilla/5.0 ... AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91 Safari/537.36
所以现在所有浏览器的 User-Agent 都包含"Mozilla",非常魔幻。
5.6 Cookie
用途:客户端存储少量数据,每次请求自动发送给服务器。
工作流程:
1. 客户端首次访问
GET / HTTP/1.1
2. 服务器设置 Cookie
HTTP/1.1 200 OK
Set-Cookie: session_id=abc123;Path=/; HttpOnly
3. 客户端后续请求自动带上 Cookie
GET /profile HTTP/1.1
Cookie: session_id=abc123
4. 服务器根据 session_id 识别用户
Cookie 属性:
Path=/:Cookie 的有效路径Domain=example.com:Cookie 的有效域名Expires=...:过期时间HttpOnly:禁止 JavaScript 访问(防止 XSS 攻击)Secure:只在 HTTPS 下发送
5.7 Referer
用途:标识请求的来源页面。
用户在 www.google.com 搜索,点击搜索结果跳转到 www.example.com
GET / HTTP/1.1
Host: www.example.com
Referer: https://www.google.com/search?q=example
应用场景:
- 统计流量来源
- 防盗链(检查 Referer,拒绝非法引用)
- 安全检查(防止 CSRF 攻击)
5.8 Accept 系列
客户端告诉服务器自己能接受什么类型的内容。
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Accept:能接受的内容类型Accept-Encoding:能接受的压缩算法Accept-Language:能接受的语言
q值表示优先级(0-1),默认 1.0。
六、本篇总结
6.1 核心要点
HTTP 方法:
- GET:获取资源,参数在 URL,幂等
- POST:提交数据,参数在 Body,非幂等
- HEAD:获取响应头,不返回 Body
- PUT:更新资源,幂等
- DELETE:删除资源,幂等
- OPTIONS:查询支持的方法
HTML 表单:
- GET 表单:参数拼接到 URL
- POST 表单:参数在 Body
- Content-Type:application/x-www-form-urlencoded、multipart/form-data、application/json
HTTP 状态码:
- 1xx:信息性(100 Continue)
- 2xx:成功(200 OK、201 Created、204 No Content)
- 3xx:重定向(301、302、304)
- 4xx:客户端错误(400、401、403、404)
- 5xx:服务器错误(500、502、503、504)
重定向:
- 301 永久重定向:网站换域名、搜索引擎更新索引
- 302 临时重定向:登录跳转、搜索引擎保留原索引
- Location 字段指定目标 URL
常见 Header:
- Content-Type:Body 的媒体类型
- Content-Length:Body 的字节长度
- Host:请求的主机名和端口
- User-Agent:客户端软件环境
- Cookie:客户端存储数据
- Referer:请求来源页面
6.2 容易混淆的点
- GET 和 POST 的本质区别:语义不同(获取 vs 提交),GET 幂等、POST 非幂等。"GET 不安全、POST 安全"是错的。
- 301 和 302 的选择:永久改变用 301,临时跳转用 302。搜索引擎对待它们完全不同。
- 401 和 403 的区别:401 是未认证(未登录),403 是无权限(登录了但权限不足)。
- Content-Type 和 Accept:Content-Type 是发送方声明数据类型,Accept 是接收方声明能接受的类型。
- Referer 的拼写:HTTP 协议中拼成了"Referer"(少了一个 r),这是历史遗留的拼写错误,但已经无法修改。
- User-Agent 为什么都有 Mozilla:历史原因,所有现代浏览器都在 User-Agent 中加入了"Mozilla"以实现兼容性。


