requests.post() 返回400主因是请求格式不符后端预期:Content-Type与data/json参数不匹配、payload字段类型/结构错误、Host头丢失或headers全量覆盖、手动设错Content-Length等。

绝大多数情况,requests.post() 返回 400 不是因为服务器拒收,而是你发出去的请求体或头没对上后端的解析预期——它根本没机会执行业务逻辑,就在网关或框架层被拦下了。
Content-Type 和 data/json 参数不匹配
这是最常踩的坑。用 data= 发送字典但没设 Content-Type,或者设了 "application/json" 却没把数据 JSON 序列化,服务器一读就懵。
-
data=是原样发送字节流,不会自动编码,也不会自动加Content-Type;你得自己json.dumps()+ 手动设头 -
json=是 requests 封装好的快捷方式:自动json.dumps()、自动设Content-Type: application/json、自动处理 Unicode 编码 - 如果你混用——比如
json=payload还手动加"Content-Type": "application/x-www-form-urlencoded",后端直接 400
payload 中字段类型或结构不符合 API 要求
后端往往对字段做强校验,尤其布尔、数字、嵌套结构。比如 "stream": "false"(字符串)和 "stream": False(布尔)在 Python 里看着像,但 JSON 解析后完全不同。
- 检查错误响应体,常见返回类似:
{"error": {"message": "'stream' must be Boolean"}} - Python 字典里的
True/False会正确序列化为 JSON 的true/false;而"true"或1不会 - 嵌套字段名拼错、漏掉必填字段(如
"messages"数组为空或格式不对)、字段值类型错(如传字符串给期望整数的"age")都会触发 400
Host 头丢失或自定义 headers 覆盖了关键默认头
requests 默认会加 Host、User-Agent 等基础头。一旦你传了 headers= 参数,requests 就完全用你给的 dict 替换默认头——Host 消失,某些严格配置的 Nginx 或云网关会直接 400。
立即学习“Python免费学习笔记(深入)”;
- 不要全量覆盖:用
headers = {**default_headers, "Authorization": "Bearer ..."}合并,或只传你需要加/改的头 - 如果必须自定义,至少补上
"Host": "your-domain.com"(注意不是 URL 里的 host,是实际域名) -
Content-Length通常由 requests 自动计算,但若你手动设了错误值,也可能被中间件拒绝
真正难排查的点往往藏在「你以为没问题」的地方:比如文档写的是 json= 格式,你却用了 data= + json.dumps(),结果多了一层引号变成字符串;又或者测试环境开了 CORS 预检,但 OPTIONS 请求失败后浏览器静默吞掉真实错误。建议先用 curl -v 或 Postman 对照发一次,比对着代码猜快得多。


















