3、HTTP协议基础:HTTP请求与响应结构、HTTP方法、HTTP状态码、HTTP头部字段
做端口复用抓包,说白了就是在跟HTTP协议打交道。你连HTTP长什么样都认不出来,那抓到的包就是一堆乱码。我刚开始学抓包那会儿,就吃过这个亏——盯着十六进制看了半天,啥也没看出来。
这一章,咱们把HTTP协议的老底翻出来看看。不搞那些虚的,直接上干货。
3.1 HTTP请求长什么样?
一个HTTP请求,说白了就三部分:请求行、请求头、请求体。我习惯叫它“三件套”。
咱们直接看一个真实的GET请求长啥样:
GET /api/user/info HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: application/json
Connection: keep-alive
看到了吗?第一行就是请求行。它告诉服务器三件事:用什么方法(GET)、访问哪个资源(/api/user/info)、用哪个协议版本(HTTP/1.1)。
从第二行开始,一直到空行之前,都是请求头。每一行都是一个键值对,用冒号隔开。空行之后是请求体,GET请求一般没有请求体。
关键点:空行是请求头和请求体的分界线。抓包的时候,如果你看到连续两个换行符(\r\n\r\n),那就是头部结束了,后面就是请求体。
3.2 HTTP响应长什么样?
响应和请求的结构差不多,也是三部分:状态行、响应头、响应体。咱们看个例子:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 128
Date: Mon, 15 Jan 2024 08:30:00 GMT
Server: nginx/1.24.0
{"code":0,"data":{"name":"张三","age":28}}
状态行里,HTTP/1.1是协议版本,200是状态码,OK是状态描述。响应头和请求头格式一样,也是键值对。空行后面就是响应体,这里返回了一段JSON数据。
抓包小技巧:我习惯先看状态行,再看Content-Length。Content-Length告诉你要读多少字节的响应体。如果服务器没发这个头,那就得靠chunked编码来分段读取了。
3.3 HTTP方法:不只是GET和POST
很多人以为HTTP方法就GET和POST两种。其实远不止这些。我整理了一张表,把常用的都列出来了:
| 方法 | 含义 | 是否有请求体 | 幂等性 |
|---|---|---|---|
| GET | 获取资源 | 否 | 是 |
| POST | 创建资源 | 是 | 否 |
| PUT | 更新资源(全量) | 是 | 是 |
| DELETE | 删除资源 | 否 | 是 |
| PATCH | 更新资源(部分) | 是 | 否 |
| HEAD | 获取响应头(无响应体) | 否 | 是 |
| OPTIONS | 查询服务器支持的方法 | 否 | 是 |
这里有个概念叫“幂等性”。说白了就是:同一个请求执行一次和执行多次,结果是一样的。GET、PUT、DELETE都是幂等的。POST不是——你提交两次订单,那就下了两单,这能一样吗?
避坑指南:我曾经遇到过一个线上问题,客户端重试机制没做好,把POST请求重发了三次,结果数据库里多了三条重复记录。所以,非幂等方法一定要做好去重。
3.4 HTTP状态码:服务器在说什么?
状态码是服务器给你的“暗号”。我把它分成五类,记起来就简单了:
- 1xx(信息类):服务器收到了请求,正在处理。比如101 Switching Protocols,WebSocket升级时就会用到。
- 2xx(成功类):请求处理成功。200 OK最常见,201 Created表示资源创建成功。
- 3xx(重定向类):需要进一步操作。301永久重定向,302临时重定向,304 Not Modified用于缓存。
- 4xx(客户端错误):你发的东西有问题。400 Bad Request,401未授权,403禁止访问,404找不到资源。
- 5xx(服务器错误):服务器出问题了。500内部错误,502 Bad Gateway,503服务不可用。
抓包的时候,我第一眼就看状态码。如果是4xx,那八成是客户端的问题;如果是5xx,那就是服务器背锅了。但有时候也不绝对——我遇到过502其实是客户端发了非法请求导致的,服务器只是背了黑锅。
3.5 HTTP头部字段:协议的“元数据”
头部字段才是HTTP协议的精华。我把它分成四类,方便记忆:
3.5.1 通用头部
请求和响应都能用的头部:
- Date:消息发送的时间。抓包时可以用来排查时间不同步的问题。
- Connection:连接管理。keep-alive表示长连接,close表示短连接。
- Cache-Control:缓存策略。no-cache、max-age这些值经常见到。
3.5.2 请求头部
客户端告诉服务器自己的“底细”:
- Host:目标主机名。HTTP/1.1强制要求必须有这个头。
- User-Agent:客户端类型。浏览器、curl、爬虫,一看就知道。
- Accept:客户端能接收的内容类型。比如Accept: application/json。
- Cookie:携带的会话信息。端口复用场景下,Cookie经常被用来做会话保持。
- Referer:请求来源。防盗链就靠它。
3.5.3 响应头部
服务器告诉客户端自己的“情况”:
- Content-Type:响应体的MIME类型。text/html、application/json最常见。
- Content-Length:响应体长度。抓包时这个值一定要和实际数据对得上。
- Set-Cookie:服务器要求客户端保存的Cookie。
- Location:重定向的目标URL。配合3xx状态码使用。
3.5.4 实体头部
描述请求体或响应体的属性:
- Content-Encoding:压缩方式。gzip、deflate最常见。
- Content-Language:内容语言。zh-CN、en-US这些。
- Last-Modified:资源最后修改时间。配合If-Modified-Since做条件请求。
- ETag:资源唯一标识。比Last-Modified更精确。
抓包实战经验:我排查端口复用问题时,最常看的是Host、Connection、Content-Length这三个头。Host用来确认请求发到了哪个后端,Connection看连接是否被复用,Content-Length用来判断消息是否完整。
3.6 一张图看懂HTTP协议
说了这么多,咱们用一张SVG图把HTTP请求-响应的完整流程串起来。这样你脑子里就有个清晰的框架了。
这张图把整个流程串起来了。客户端先发请求,服务器处理后返回响应。请求和响应各有三部分结构,状态码告诉你处理结果。抓包的时候,你就盯着这几个关键点看,基本不会跑偏。
3.7 抓包时怎么看HTTP协议?
最后,我分享几个抓HTTP包的小习惯:
- 先看请求行:方法、URL、协议版本。确认客户端到底想干什么。
- 再看状态码:服务器给了什么回应。4xx还是5xx,心里先有个数。
- 然后看Host头:确认请求发到了哪个域名。端口复用场景下,这个头特别重要。
- 接着看Content-Length:和实际数据长度对比。对不上就说明有问题。
- 最后看响应体:是不是你期望的数据格式。JSON还是HTML,一眼就能看出来。
避坑指南:我曾经遇到过一个诡异的问题——抓包看到请求发出去了,服务器也返回200了,但客户端就是收不到响应。最后发现是Content-Length写错了,比实际数据小了100个字节。客户端读完指定长度就停了,剩下的数据被当成下一个请求处理了。所以,Content-Length这个值,一定要仔细核对。
HTTP协议看着简单,但坑不少。把这些基础打牢了,后面讲端口复用抓包的时候,你才能一眼看出问题出在哪。