Python requests模块headers传参语法导致API返回异常问题
问题背景
编写简易接口测试脚本时,使用Python requests库对两个不同API发起GET请求,采用相同的传参写法得到了差异极大的响应结果,具体表现如下。
错误传参写法测试结果
未显式指定headers关键字参数,直接将请求头字典作为位置参数传入,执行结果:
>> import requests >> head1 = { 'key' : 'API-key1' } >> url1 = 'https://url1.com' >> r1 = requests.get(url1, head1) ## Notice headers=head1 wasn't used >> print(r1) <Response [200]> ## Yet a valid response prints out >> print(r1.json()) {'response': 'valid response'} >> head2 = { 'key' : 'API-key2' } >> url2 = 'https://url2.com' >> r2 = requests.get(url2, head2) ## But in this instance >> print(r2) <Response [401]> >> print(r2.json()) ## I get an 401 error <bound method Response.json of <Response [401]>>
标准传参写法测试结果
改用官方推荐写法,显式通过headers=xxx关键字传参,执行结果:
>> import requests >> head1 = { 'key' : 'API-key1' } >> url1 = 'https://url1.com' >> r1 = requests.get(url1, headers=head1) ## Using the correct syntax >> print(r1) <Response [200]> >> print(r1.json()) ## But it received an error {'response': {'error': [{'msg': 'No API access key supplied'}]}} >> head2 = { 'key' : 'API-key2' } >> url2 = 'https://url2.com' >> r2 = requests.get(url2, headers=head2) ## This works >> print(r2) <Response [200]> >> print(r2.json()) {'response': 'valid response'}
原因解答
核心前提:requests.get()的官方函数签名为get(url, params=None, **kwargs),第二个位置参数是params(对应URL问号后拼接的查询参数),headers属于关键字参数,必须显式通过headers=xxx的形式传入。如果直接把字典作为第二个位置参数传入,这个字典不会被当做请求头处理,会被自动序列化为URL查询参数附加到请求地址末尾。
两个API的表现差异完全来自接口本身的鉴权逻辑设计区别:
- 第二个API的实现符合常规接口设计规范:
- 鉴权逻辑仅从请求头中读取名为
key的访问凭证,不会解析URL查询参数中的同名字段 - 鉴权失败时按HTTP规范返回401状态码
错误传参时凭证被拼到URL参数里,请求头无有效凭证,返回401;正确传参时凭证在请求头中被正常读取,返回200有效响应,表现完全符合预期。
- 鉴权逻辑仅从请求头中读取名为
- 第一个API存在两处不规范的实现问题,是导致反常表现的根本原因:
- 鉴权逻辑仅支持从URL查询参数中读取名为
key的访问凭证,没有实现从请求头读取凭证的逻辑,也没有使用行业通用的请求头鉴权字段(比如Authorization、X-API-Key等)。错误传参时key字段刚好被拼到URL查询参数中,歪打正着满足了鉴权要求,所以返回有效响应;正确传参时key被放到请求头里,接口读不到凭证,就返回了「未提供API访问密钥」的错误。 - 鉴权失败时没有按HTTP规范返回401状态码,所有场景统一返回200状态码,仅在响应体内标注错误信息,很容易误导调用方判断请求状态。
- 鉴权逻辑仅支持从URL查询参数中读取名为
另外测试中打印第二个API401响应时出现<bound method Response.json of <Response [401]>>,是编写代码时漏写了json后的调用括号(),属于手误导致的小问题,和接口逻辑、传参逻辑无关,补上括号即可正常打印响应内容。
内容的提问来源于stack exchange,提问作者janielle
相关产品推荐
相关产品推荐

