Python Requests发送HTTP POST时TCP包拆分致API请求失败排查
解决Python requests/urllib3 POST请求因数据包拆分报错的问题
这个问题我之前也碰到过,大概率是目标API**不支持HTTP分块传输编码(Chunked Transfer Encoding)**导致的!
问题根源
curl默认会提前计算请求体的总长度,设置Content-Length头部,把整个请求打包成单一数据包发送;而Python的requests/urllib3当请求体大小超过内部阈值(通常是1KB左右)时,会自动启用分块传输,将请求体拆分成多个数据包发送。很多老旧或者实现不规范的API无法正确解析分块传输的请求,所以会返回错误响应。
解决方案:强制禁用分块传输
下面针对不同库给出具体实现:
1. 使用requests库的两种方法
方法一:自定义适配器全局禁用分块
import requests from requests.adapters import HTTPAdapter class NoChunkAdapter(HTTPAdapter): def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): # 移除分块传输的头部 request.headers.pop('Transfer-Encoding', None) # 手动计算并设置Content-Length if request.body is not None: request.headers['Content-Length'] = str(len(request.body)) return super().send(request, stream, timeout, verify, cert, proxies) # 初始化会话并挂载适配器 session = requests.Session() session.mount('https://your-api-domain.com', NoChunkAdapter()) # 发送请求 payload = {"key1": "value1", "key2": "value2"} headers = {"Content-Type": "application/json", "X-Custom-Header": "your-value"} response = session.post('https://your-api-domain.com/target-endpoint', json=payload, headers=headers) print(response.status_code) print(response.text)
方法二:手动序列化JSON并设置Content-Length
import requests import json payload = {"key1": "value1", "key2": "value2"} # 手动序列化JSON,避免requests自动处理 json_payload = json.dumps(payload) headers = { "Content-Type": "application/json", # 计算并设置内容长度 "Content-Length": str(len(json_payload)) } response = requests.post( 'https://your-api-domain.com/target-endpoint', data=json_payload, headers=headers, # 禁用流式传输(避免分块) stream=False ) print(response.status_code) print(response.text)
2. 使用urllib3库的解决方案
import urllib3 import json payload = {"key1": "value1", "key2": "value2"} json_payload = json.dumps(payload) headers = { "Content-Type": "application/json", "Content-Length": str(len(json_payload)) } http = urllib3.PoolManager() response = http.request( 'POST', 'https://your-api-domain.com/target-endpoint', body=json_payload, headers=headers, # 明确禁用分块传输 chunked=False ) print(response.status) print(response.data.decode('utf-8'))
验证方式
修改代码后,再用Wireshark抓包,确认Python发送的请求是单一数据包,且包含正确的Content-Length头部,没有Transfer-Encoding: chunked字段,这样就和curl的请求格式一致了,API应该就能正常响应。
内容的提问来源于stack exchange,提问作者Christian H
相关产品推荐
相关产品推荐

