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请求-响应的完整流程串起来。这样你脑子里就有个清晰的框架了。

HTTP请求-响应完整流程 客户端 (浏览器/APP/curl) 服务器 (Nginx/Apache/Tomcat) ① 发送HTTP请求 HTTP请求结构 请求行:GET /api HTTP/1.1 请求头:Host、User-Agent... 空行:\r\n 请求体:JSON/表单数据... HTTP响应结构 状态行:HTTP/1.1 200 OK 响应头:Content-Type... 空行:\r\n 响应体:HTML/JSON... ② 返回HTTP响应 状态码分类速查 1xx 信息类 → 101 Switching Protocols 2xx 成功类 → 200 OK / 201 Created 3xx 重定向类 → 301 / 302 / 304 4xx 客户端错误 → 400 / 401 / 403 / 404 5xx 服务器错误 → 500 / 502 / 503

这张图把整个流程串起来了。客户端先发请求,服务器处理后返回响应。请求和响应各有三部分结构,状态码告诉你处理结果。抓包的时候,你就盯着这几个关键点看,基本不会跑偏。

3.7 抓包时怎么看HTTP协议?

最后,我分享几个抓HTTP包的小习惯:

  1. 先看请求行:方法、URL、协议版本。确认客户端到底想干什么。
  2. 再看状态码:服务器给了什么回应。4xx还是5xx,心里先有个数。
  3. 然后看Host头:确认请求发到了哪个域名。端口复用场景下,这个头特别重要。
  4. 接着看Content-Length:和实际数据长度对比。对不上就说明有问题。
  5. 最后看响应体:是不是你期望的数据格式。JSON还是HTML,一眼就能看出来。

避坑指南:我曾经遇到过一个诡异的问题——抓包看到请求发出去了,服务器也返回200了,但客户端就是收不到响应。最后发现是Content-Length写错了,比实际数据小了100个字节。客户端读完指定长度就停了,剩下的数据被当成下一个请求处理了。所以,Content-Length这个值,一定要仔细核对。

HTTP协议看着简单,但坑不少。把这些基础打牢了,后面讲端口复用抓包的时候,你才能一眼看出问题出在哪。