我正在尝试向具有两个具有相同名称但不同值的标头的服务器发送GET请求:
url = 'whatever'
headers = {'X-Attribute': 'A', 'X-Attribute': 'B'}
requests.get(url, headers = headers)
很明显这样行不通,因为请求头字典不能包含两个键X-Attribute
。
我能做些什么吗?比如说,我可以将headers传递为字典以外的其他内容吗?以这种方式发送请求是服务器的一个特性,我无法改变它。
我正在尝试向具有两个具有相同名称但不同值的标头的服务器发送GET请求:
url = 'whatever'
headers = {'X-Attribute': 'A', 'X-Attribute': 'B'}
requests.get(url, headers = headers)
很明显这样行不通,因为请求头字典不能包含两个键X-Attribute
。
我能做些什么吗?比如说,我可以将headers传递为字典以外的其他内容吗?以这种方式发送请求是服务器的一个特性,我无法改变它。
requests
库将请求头存储在一个dict
中,这意味着每个头只能出现一次。因此,如果不对requests
库本身进行更改,就无法发送具有相同名称的多个头。
然而,如果服务器符合HTTP1.1标准,它必须能够将其视为一个带有逗号分隔值列表的头。
晚些编辑:
既然引起了我的关注,使这个工作的方法是使用一个自定义的str
实例,在字典中存储多个相同值,通过以不同的方式实现哈希协议(或者实际上在CaseInsensitiveDict
中使用lower()
)来实现。例如:
class uniquestr(str):
_lower = None
def __hash__(self):
return id(self)
def __eq__(self, other):
return self is other
def lower(self):
if self._lower is None:
lower = str.lower(self)
if str.__eq__(lower, self):
self._lower = self
else:
self._lower = uniquestr(lower)
return self._lower
r = requests.get("https://httpbin.org/get", headers={uniquestr('X'): 'A',
uniquestr('X'): 'B'})
print(r.text)
生成类似于:
{ ... "headers": { ... "X": "A,B", }, ... }
有趣的是,在响应中,头信息被合并了,但它们实际上被发送为两行独立的头。
headers={'X-Attribute': 'name=value\r\nX-Attribute: name=value'}
。然而,这并不是一个非常好的解决方案... - matarequests在底层使用urllib2.urlencode(或类似方法)来编码头信息。
这意味着可以将元组列表作为有效载荷参数发送,而不是字典,从而使头信息列表不再受字典强制的唯一键约束限制。发送元组列表的方法在urlib2.urlencode文档中有说明。http://docs.python.org/2/library/urllib.html#urllib.urlencode
以下代码将解决问题,无需展开或使用不良编程技巧:
url = 'whatever'
headers = [('X-Attribute', 'A'),
('X-Attribute', 'B')]
requests.get(url, headers = headers)
现在,Requests将所有头信息(发送和接收)都存储在大小写不敏感的字典中。除此之外,在打开Python控制台并编写以下代码:
headers = {'X-Attribute':'A', 'X-Attribute':'B'}
{'X-Attribute': 'A'} # or {'X-Attribute': 'B'}, we can never be certain which it will be
您可以尝试(但不会起作用)的方法是:
headers = [('X-Attribute', 'A'), ('X-Attribute', 'B')]
但至少这将是完全定义的行为(您将始终发送B)。正如@mata建议的那样,如果您的服务器符合HTTP/1.1
标准,您可以这样做:
import collections
def flatten_headers(headers):
for (k, v) in list(headers.items()):
if isinstance(v, collections.Iterable):
headers[k] = ','.join(v)
headers = {'X-Attribute': ['A', 'B', ..., 'N']}
flatten_headers(headers)
requests.get(url, headers=headers)
url = 'whatever'
headers = {'X-Attribute': "A,B"}
requests.get(url, headers = headers)
X-Attribute:name=value
。 - Stefan