Python Requests POST请求返回400而非200,请求排查问题
排查Python Requests POST请求400错误的问题
让我帮你一步步揪出这个400错误的根源,先看代码里几个明显的问题:
1. Headers里的格式错误与冗余设置
- Origin和Referer的URL多了空格:你写的
"Origin" : "https: //www.bonuscard.ch"和"Referer" : "https: //www.bonuscard.ch/myos/en/login"中,https:后面的空格是多余的,应该改成https://——这种格式错误会直接被服务器判定为无效请求。 - 手动硬编码Content-Length:你在headers里固定了
"Content-Length" : "151",但Requests会自动根据你发送的payload计算并设置这个头。手动设置的话,一旦实际payload长度和这个数值不匹配,服务器就会返回400,直接删掉这个头即可。
2. Payload的键包含多余空格
你的payload里几个字段的键末尾都带了空格,比如:
"userName-border:userName-border_body:userName ": "jon@doe.com", "password-border:password-border_body:password ": "123", "login " : ""
服务器端的表单字段名是没有这些空格的,必须和页面上表单元素的name属性完全一致(可以通过浏览器开发者工具查看真实字段名),把这些多余空格去掉。
3. Hidden Token的处理逻辑错误
你获取了hidden元素的id作为payload的键,但这类CSRF token通常是通过name属性提交的,而且它的value属性不是空字符串——你需要获取这个元素的value值,而不是把键对应的内容设为空。比如调整token的获取逻辑:
# 先打印查看hidden元素的真实属性,确认name和value hidden_elements = SELECTOR(tree) for elem in hidden_elements: print(elem.attrib) # 假设第一个hidden元素是需要的token,取它的name和value token_name = hidden_elements[0].get('name') token_value = hidden_elements[0].get('value')
再把这个键值对加入payload,而不是设为空字符串。
修改后的示例代码
import requests import lxml.html from lxml.cssselect import CSSSelector SELECTOR = CSSSelector('[type=hidden]') BASE_URL = 'https://www.bonuscard.ch/myos/en/login' LOGIN_URL = BASE_URL + '1.IFormSubmitListener-homePanel-loginPanel-loginForm' # 修正后的headers:去掉冗余的Content-Length,修正URL空格 headers = { "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en,de;q=0.9", "Cache-Control": "no-cache", "Connection": "keep-alive", "Content-Type": "application/x-www-form-urlencoded", "DNT": "1", "Host": "www.bonuscard.ch", "Origin": "https://www.bonuscard.ch", "Pragma": "no-cache", "Referer": "https://www.bonuscard.ch/myos/en/login", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36" } with requests.Session() as session: response = session.get(BASE_URL) tree = lxml.html.fromstring(response.content) hidden_elements = SELECTOR(tree) # 获取正确的token键值对 token_name = hidden_elements[0].get('name') token_value = hidden_elements[0].get('value') payload = { token_name: token_value, "userName-border:userName-border_body:userName": "jon@doe.com", "password-border:password-border_body:password": "123", "login": "" } response = session.post(LOGIN_URL, headers=headers, data=payload) print(response.status_code) print(response.text) # 可以查看服务器返回的具体错误信息,进一步排查
额外提示
- 不要用
json=payload发送请求,因为服务器预期的是application/x-www-form-urlencoded格式,不是JSON。 - 如果还是有问题,可以用
requests.utils.dump_response(response)打印出实际发送的请求详情,对比浏览器开发者工具Network面板里的请求,看看哪里还有差异。
内容的提问来源于stack exchange,提问作者jjk
相关产品推荐
相关产品推荐

