问题与目标
请求失败时,“网络有问题”太笼统。域名、IP、端口、TCP、HTTP 状态和响应格式属于不同层次,只有逐层判断才能定位故障。
完成标准:能解释一次 HTTP 请求经过的主要层次,使用 Python 发送带超时的 JSON 请求,并区分连接错误、超时、非成功状态和响应解析错误。
核心概念
IP 标识网络中的主机接口,端口标识主机上的服务,TCP 提供可靠字节流,HTTP 在其上定义请求与响应语义。URL http://127.0.0.1:8000/tasks 同时给出协议、主机、端口和路径。
一次 HTTPS 请求可以按层次理解:域名先经 DNS 得到 IP,客户端与目标端口建立 TCP 连接,再通过 TLS 验证身份和加密通道,最后交换 HTTP 消息。某一层失败,不应笼统归因于“接口错误”。
HTTP/1.1 请求由请求行、请求头、空行和可选请求体组成:
POST /tasks?notify=false HTTP/1.1
Host: 127.0.0.1:8000
Content-Type: application/json
{"title":"inspect HTTP message"}
响应对应状态行、响应头、空行和响应体。请求头描述元数据,JSON 属于请求体;Content-Type 说明当前内容格式,Accept 表达客户端希望接收的格式。
HTTP 方法表达意图:GET 读取,POST 创建,PUT 通常整体替换,PATCH 部分修改,DELETE 删除。状态码分组:2xx 成功,4xx 表示请求侧问题,5xx 表示服务侧失败。
超时应显式设置。重试只适合短暂故障,并应限制次数、增加退避;非幂等写请求不能在没有幂等设计时随意重试。
可运行实现
先启动本地示例服务:
python -m http.server 8000
安装 requests,并保存 http_client.py:
python -m pip install requests
from time import sleep
import requests
def get_text(url: str, attempts: int = 3) -> str:
for current in range(1, attempts + 1):
try:
response = requests.get(url, timeout=(1.0, 3.0))
response.raise_for_status()
return response.text
except (requests.Timeout, requests.ConnectionError):
if current == attempts:
raise
sleep(0.2 * current)
raise RuntimeError("不可达分支")
if __name__ == "__main__":
body = get_text("http://127.0.0.1:8000/")
print(body[:80])
timeout=(连接超时, 读取超时) 防止请求无限等待。若接口应返回 JSON,再单独调用 response.json(),并处理 JSON 解码失败;状态成功并不保证响应一定是 JSON。
对 02.17 的本地 API 发送 JSON 请求:
import requests
payload = {"title": "understand request body"}
response = requests.post(
"http://127.0.0.1:8000/tasks",
params={"notify": "false"},
json=payload,
headers={"Accept": "application/json"},
timeout=(1.0, 3.0),
)
response.raise_for_status()
data = response.json()
print(data["id"], data["title"])
params 生成查询字符串,json 负责 JSON 序列化并设置相应内容类型。需要复用连接和公共请求头时使用 requests.Session(),但 Session 也要在明确的生命周期内关闭。
命令行分层检查可使用:
getent hosts example.com
ss -lntp | grep ':8000'
curl -v --max-time 5 http://127.0.0.1:8000/
curl -v 中以 > 开头的是发出的请求,以 < 开头的是收到的响应。它可以证明 HTTP 交互到了哪一步,但包含认证头时不要把完整调试输出粘贴到公开记录。
常见问题与排查
Connection refused:目标主机可达,但端口没有服务监听或被明确拒绝。- 连接超时:地址不可达、防火墙丢包或网络路径异常。
- 读取超时:连接已建立,但服务迟迟未返回数据。
- 404:服务可访问,但路径不匹配;500:请求到达服务,处理过程失败。
response.json()报错:检查Content-Type和原始响应片段,代理错误页常返回 HTML。- 在
async def中直接调用requests:它仍是同步阻塞调用,应改用异步 HTTP 客户端或线程适配。
小结
网络排查从底向上看地址解析、连接、HTTP 状态和业务响应。客户端的最低可靠性要求是显式超时、有限重试、状态检查和格式检查。
许可协议:CC BY-NC 4.0
更新于 2 小时前
觉得文章有帮助?点个赞吧!
0 条评论


