Python requests请求头含冒号前缀非法字符报错如何解决
问题根因
你在开发者工具里看到的:authority、:method、:path、:scheme属于HTTP/2协议的伪首部,不是用户可自定义的普通HTTP请求头。这些字段是HTTP/2传输帧层面的内置字段,浏览器开发者工具会把它们和普通请求头放在一起展示,但所有合规的HTTP客户端都会在发起请求时自动生成这些字段,不需要手动传入。你手动把它们加到headers字典里,反而触发了requests的头名校验规则——普通自定义头不允许以冒号开头,所以直接抛出非法字符错误。
修复步骤
- 直接删除headers字典里所有以冒号开头的四个键值对,你引入的
HTTP20Adapter会在发起HTTP/2连接时自动生成符合规范的伪首部,不需要手动配置。 - 修正请求地址的协议:你代码里挂载适配器、发起请求用的都是
http://开头的地址,必须改成https://,否则HTTP/2的TLS握手会直接失败,根本发不出请求。 - 删除手动填写的
content-length头,这个字段由requests根据你提交的请求体自动计算长度生成,手动传值如果和实际请求体长度不匹配,会直接导致请求异常。 - 补充POST请求的请求体:你当前代码只传了头,没有带Boost接口要求的表单参数,就算请求头全对,接口也会返回参数错误,你可以回到浏览器Network面板,点开Boost请求的Payload标签,把对应的参数复制下来,传到requests.post的
data参数里。
修正后的核心代码参考
import requests from hyper.contrib import HTTP20Adapter def main(): person = input('Insert page link (e.g kristian-ramey)\n') headers = { 'accept': '*/*', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'en-US,en;q=0.9,es;q=0.8,fr;q=0.7', 'content-type': 'application/x-www-form-urlencoded', 'cookie': '__aaxsc=1; _ga=GA1.2.1274875939.1657675345; _gid=GA1.2.109078920.1657675345; lookup=las+vegas; XSRF-TOKEN=eyJpdiI6InZvNmdIXC9hSmhPRzZVelpRMVwvNUV4Zz09IiwidmFsdWUiOiJrbGJYZWloaUpjbnp4cVFCXC8xSndoSmxudmxLbjU5aG9cL2NCWW5qSWVWZ0lJZjVZbzY3ZWRwWlI3ZFZiTnJLZHYiLCJtYWMiOiJkYWViNjNlZmIxODc1ZTllOWM5OGEzMmM0ZTkxMGMzODA2ZTA4MDMyODQ1OWFjYzA4MzQyNDgzMmZjNjQ4ODY0In0%3D; laravel_session=eyJpdiI6Ino1QkR6TTBGaU1kSFBhSjZNMUhMWFE9PSIsInZhbHVlIjoicFwvaVh0TUpReWxmS0pJVzVsV3JzUUlBOGpUKzYySjlwcEdzcTN1ZTlLNUVTenpqazFuZkRsa2xBNWFRT0JRbnkiLCJtYWMiOiJlZDhlODBhMTVjOTYxYzRlZDAxM2JhMGZjYzVkMWE0NmY0NGQyOTkwMmIwNWJhMmNmYmEyYzc0MGVhYTU3OWYzIn0%3D; aasd=8%7C1657676628018', 'origin': 'https://www.famousbirthdays.com', 'referer': f'https://www.famousbirthdays.com/people/{person}.html', 'sec-ch-ua': '".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-origin', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36' } session = requests.session() # 挂载适配器时用https协议,匹配站点根路径即可,不需要写完整接口路径 session.mount('https://www.famousbirthdays.com', HTTP20Adapter()) # 替换成你从浏览器Payload里复制的接口参数 post_data = {"slug": person} r = session.post('https://www.famousbirthdays.com/api/people/boost', headers=headers, data=post_data) print(r.text) print(r.status_code) if __name__ == "__main__": main()
注:不要尝试绕过requests的头名校验规则,这类校验是为了符合HTTP协议规范,就算你强行修改底层逻辑把冒号开头的头传进去,服务端收到不符合HTTP/2规范的请求也会直接拒绝,完全没必要。
内容的提问来源于stack exchange,提问作者vey
相关产品推荐
相关产品推荐

