我正在尝试向具有两个名称相同但值不同的标头的服务器发送 GET 请求:
url = 'whatever'
headers = {'X-Attribute': 'A', 'X-Attribute': 'B'}
requests.get(url, headers = headers)
这显然不起作用,因为 headers 字典不能包含两个 key X-Attribute
。
有什么我可以做的,即我可以将标题作为字典以外的东西传递吗?以这种方式发送请求的要求是服务器的特性,我无法更改。
我正在尝试向具有两个名称相同但值不同的标头的服务器发送 GET 请求:
url = 'whatever'
headers = {'X-Attribute': 'A', 'X-Attribute': 'B'}
requests.get(url, headers = headers)
这显然不起作用,因为 headers 字典不能包含两个 key X-Attribute
。
有什么我可以做的,即我可以将标题作为字典以外的东西传递吗?以这种方式发送请求的要求是服务器的特性,我无法更改。
requests
将请求标头存储在 a 中dict
,这意味着每个标头只能出现一次。因此,如果不对库本身进行更改,requests
就不可能发送多个具有相同名称的标头。
但是,如果服务器符合 HTTP1.1,它必须能够接受与带有逗号分隔的单个值列表的标头相同的内容。
后期编辑:
由于这引起了我的注意,因此实现这项工作的一种方法是使用一个自定义实例,str
该实例允许dict
通过不同地实现哈希合约(或实际上在 aCaseInsensitiveDict
中存储多个相同的值)用于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)
产生类似的东西:
{ ... “标题”:{ ... “X”:“A,B”, }, ... }
有趣的是,在响应中,标头是组合在一起的,但它们实际上是作为两个单独的标头行发送的。
requests 在后台使用 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)