Python requests POST请求被重定向为GET的问题及解决方法
我调用一个同时支持GET和POST请求的REST API接口,期望发送POST请求。用ThunderClient插件发送POST请求一切正常,能获取正确数据,但用Python的requests库发送时遇到问题:
当执行以下代码:
import requests from pprint import pprint response = requests.post( url, data=payload, verify=certificate, ) pprint(response.request)
输出为<PreparedRequest [GET]>,requests库自动把请求重定向为GET,返回对应的GET响应。
如果设置allow_redirects=False:
import requests from pprint import pprint response = requests.post( url, data=payload, allow_redirects=False, verify=certificate, ) pprint(response.request)
输出为<PreparedRequest [POST]>,但response.text为空,响应头是{'Cache-Control': 'no-cache', 'Content-length': '0', 'Location': '...url...', 'Connection': 'close'},状态码为302。
想问:为什么ThunderClient没这个问题?我哪里操作错了?怎么确保发送POST请求?
1. requests与ThunderClient的行为差异
requests库默认对302重定向的处理是将POST转为GET(遵循早期HTTP规范),而ThunderClient会按照现代浏览器逻辑,保留POST方法执行重定向(等效于按307/308状态码的语义处理302),这是两者表现不同的核心原因。
2. 操作本身无错误
你没有操作失误,问题源于requests的默认重定向规则和ThunderClient不一致。
3. 确保发送POST请求的解决方案
方法一:手动处理重定向,保留POST方法
先发送POST并禁止自动重定向,拿到重定向地址后再次发送POST请求:
import requests from pprint import pprint # 首次发送POST,禁止自动重定向 first_resp = requests.post( url, data=payload, allow_redirects=False, verify=certificate, ) # 检测302重定向并发起二次POST if first_resp.status_code == 302 and 'Location' in first_resp.headers: session = requests.Session() session.verify = certificate final_resp = session.post( first_resp.headers['Location'], data=payload ) pprint(final_resp.request) print(final_resp.text)
方法二:强制重定向时保留POST方法(需requests 2.26.0+)
使用method_allowlist参数,指定重定向时允许保留POST方法:
import requests from pprint import pprint response = requests.post( url, data=payload, verify=certificate, allow_redirects=True, # 允许重定向时保留POST方法 method_allowlist=["POST", "GET"] ) pprint(response.request) print(response.text)
这个参数会让requests在处理302重定向时,沿用原POST方法,和ThunderClient行为一致。
方法三:直接POST到重定向目标地址
部分API的302只是引导到实际处理请求的地址,直接将请求发送到响应头Location中的URL,也能获取正确结果。
内容的提问来源于stack exchange,提问作者Stein

