HTTP 协议基础:请求与响应、方法、状态码、头部

说实话,做数据采集这行,HTTP 协议就是你的吃饭家伙。你写的每一个爬虫、推流的每一个请求,底层都在跟 HTTP 打交道。我见过太多新手拿着 requests 库咔咔一顿写,遇到 403、502 就懵了——说白了,就是没搞懂协议本身。

这一章,咱们把 HTTP 协议的核心掰开揉碎。不扯理论,只讲你写代码时真正用得上的东西。

HTTP 请求与响应:一次完整的对话

HTTP 协议本质上就是客户端和服务端之间的一次对话。客户端说“我要什么”,服务端回答“给你”或者“不给”。

我习惯把一次 HTTP 交互拆成两个部分来看:

  • 请求(Request):客户端发给服务端的消息,包含“我想干什么”和“附带的信息”。
  • 响应(Response):服务端返回给客户端的消息,包含“结果如何”和“你要的数据”。

举个例子,你在浏览器输入 https://api.example.com/data,浏览器会帮你构造一个 HTTP 请求,发出去。服务端处理完,返回一个响应。整个过程就这么简单。

核心要点:一个请求对应一个响应。没有响应,要么是网络断了,要么是服务端挂了。做采集时,如果发现请求发出去没回应,先检查这两点。

常见请求方法:GET 和 POST 的区别

HTTP 定义了很多方法,但咱们做数据采集和推流,最常用的就两个:GET 和 POST。其他的比如 PUT、DELETE,偶尔会遇到,但频率低得多。

特性 GET POST
语义 获取资源 提交数据
参数位置 URL 查询字符串(?key=value) 请求体(Body)
安全性 参数暴露在 URL 中,不安全 参数在 Body 中,相对安全
幂等性 是(多次请求结果相同) 否(多次请求可能产生不同结果)
数据长度限制 受 URL 长度限制(通常 2KB-8KB) 理论上无限制
缓存 可以被浏览器缓存 通常不被缓存

我在项目中遇到过一个问题:有个同事用 GET 请求提交一个很大的 JSON 数据,结果服务端一直收不到完整数据。为什么?因为 URL 长度超了,数据被截断了。后来改成 POST,问题立刻解决。

我的建议:采集数据时,如果只是拉取列表、详情页,用 GET。如果需要提交表单、上传文件、发送大量数据,用 POST。别混用,也别为了省事把 POST 的参数塞到 URL 里。

状态码:服务端在说什么?

状态码是服务端给你的“暗号”。看懂它,你就能快速定位问题。我把它分成五类:

  • 1xx(信息):服务端收到了,还在处理。日常采集基本见不到。
  • 2xx(成功):请求成功了。最常见的是 200 OK。
  • 3xx(重定向):资源挪地方了。比如 301 永久重定向,302 临时重定向。做采集时,遇到 302 要跟着跳转,否则拿不到真实数据。
  • 4xx(客户端错误):你发的东西有问题。比如 400 参数错误,401 未认证,403 禁止访问,404 资源不存在。
  • 5xx(服务端错误):服务端出问题了。比如 500 内部错误,502 网关错误,503 服务不可用。

避坑指南:我曾经写过一个采集脚本,连续遇到 403 状态码。我以为是 IP 被封了,折腾了半天代理。后来仔细一看,是请求头里忘了加 User-Agent。记住:403 不一定是封 IP,也可能是请求头不对。

下面这张图帮你快速定位常见状态码的处理方式:

HTTP 状态码快速定位图 HTTP 状态码快速定位 2xx 成功 200 OK 3xx 重定向 301 / 302 4xx 客户端错 403 / 404 5xx 服务端错 500 / 502 处理建议 2xx:直接解析数据 | 3xx:跟随重定向 | 4xx:检查请求头和参数 | 5xx:等待后重试 常见 4xx 状态码 • 400:参数格式错误 • 401:未认证(缺 Token) • 403:禁止访问(权限不足) • 404:资源不存在 • 429:请求频率过高 常见 5xx 状态码 • 500:服务器内部错误 • 502:网关错误(上游挂了) • 503:服务暂时不可用 • 504:网关超时 采集应对策略 • 2xx:直接解析 • 3xx:allow_redirects=True • 4xx:检查请求构造 • 5xx:指数退避重试

请求头与响应头:藏在背后的信息

HTTP 头部(Headers)是请求和响应里的“元数据”。它们不直接承载业务数据,但决定了请求能不能成功、响应该怎么解析。

我习惯把请求头分成三类:

  • 身份标识类:User-Agent(你是谁)、Referer(从哪来)、Cookie(会话信息)。做采集时,这三个头经常需要伪造。
  • 内容协商类:Accept(你要什么格式)、Accept-Language(你要什么语言)、Content-Type(你发的是什么格式)。
  • 控制类:Authorization(认证令牌)、Cache-Control(缓存策略)、Connection(连接管理)。

响应头里,我最关注这几个:

  • Content-Type:返回的数据是什么格式。是 JSON、HTML 还是图片?决定了你怎么解析。
  • Set-Cookie:服务端让你保存的 Cookie。下次请求要带上。
  • Location:重定向时告诉你去哪。
  • Retry-After:限流时告诉你多久后再试。

一个小技巧:我写采集脚本时,习惯先用浏览器的开发者工具(F12)看一遍请求头。把关键的 Headers 复制出来,直接用到代码里。这样能避免很多“为什么我请求失败”的问题。

一个完整的 HTTP 请求示例

下面是一个用 Python 的 requests 库发送 GET 请求的例子。注意看我是怎么设置请求头的:

import requests

url = "https://api.example.com/users"
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    "Accept": "application/json",
    "Authorization": "Bearer your_token_here"
}

response = requests.get(url, headers=headers)

# 检查状态码
if response.status_code == 200:
    data = response.json()
    print("采集成功,数据条数:", len(data))
elif response.status_code == 403:
    print("权限不足,检查 Token 或请求头")
elif response.status_code == 429:
    print("请求太频繁,等待后重试")
else:
    print(f"未知错误:{response.status_code}")

这段代码里,我手动设置了三个请求头。为什么?因为很多 API 服务会检查 User-Agent,没有的话直接拒绝。Authorization 是认证用的,不带它就拿不到数据。

我曾经踩过的坑:有一次我写推流脚本,往服务端 POST 数据,服务端一直返回 400。我检查了半天,发现是 Content-Type 没设置。默认 requests 会帮你设成 application/x-www-form-urlencoded,但服务端要的是 application/json。加上 headers={"Content-Type": "application/json"} 后,问题解决。

小结

HTTP 协议不难,但细节多。记住三点:

  • 请求方法选对(GET 拿数据,POST 发数据)
  • 状态码看懂(2xx 成功,4xx 你的问题,5xx 对方的问题)
  • 请求头别漏(User-Agent、Content-Type、Authorization 是三大护法)

把这些基础打牢,后面的采集和推流实战,你会顺手很多。