11

我正在尝试向具有两个名称相同但值不同的标头的服务器发送 GET 请求:

url = 'whatever'
headers = {'X-Attribute': 'A', 'X-Attribute': 'B'}
requests.get(url, headers = headers)

这显然不起作用,因为 headers 字典不能包含两个 key X-Attribute

有什么我可以做的,即我可以将标题作为字典以外的东西传递吗?以这种方式发送请求的要求是服务器的特性,我无法更改。

4

4 回答 4

10

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”,
  },
  ...
}

有趣的是,在响应中,标头是组合在一起的,但它们实际上是作为两个单独的标头行发送的。

于 2013-05-28T11:30:10.967 回答
4

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)
于 2013-11-11T07:31:55.520 回答
3

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)
于 2013-05-28T13:42:31.600 回答
2
url = 'whatever'
headers = {'X-Attribute': "A,B"}
requests.get(url, headers = headers)
于 2019-02-13T19:14:48.240 回答