Python - 有序标头HTTP请求

时间:2017-07-01 19:57:36

标签: python

我目前正在使用python 2.7请求库,并且不支持有序头文件。我可以将有序数据用于发布和获取(如有序字典),但根本不支持标题。甚至没有在python 3中

我知道HTTP协议RFC,表明标头的顺序是无关紧要的,但问题是我实现的第三方服务不起作用,除非标题是有序的。我知道这是因为我已经用其他语言实现了有序头文件请求并且它可以工作(比如java),是的我100%肯定,因为我检查了burp和wireshark以确保这是请求之间的唯一区别。但是我已经在python中拥有5000多行,所以由于这样的问题,迁移到那里是一个痛苦的决定。

我想到的唯一解决方案是在TCP上自己实现http协议,但这不是一个聪明的解决方案。我不能拥有与可用解决方案相同的代码质量,这可能是我的代码失败的一个方面。

请参阅下面的简化代码示例:

data=(("param1","something"),
("param2","something_else"))

headers={'id': 'some_random_number',
'version':'some_random_number' ,
'signature':'some_random_number' ,
                    'Content-Type':'application/x-www-form-urlencoded' ,
                    'charset':'utf-8' ,
                    'Content-Length':str(len(urllib.urlencode(data))) ,
                    'name':'random' ,
                    'User-Agent':'Firefox' ,
                    'Connection':'Keep-Alive' ,
                    'Accept-Encoding':'gzip'}

requests.post("myservice.com",headers=headers, data=data)

请求标题的顺序是这样发送的(不是实际的顺序,只是一个例子来说明我的观点)

'version':'some_random_number' 
'Accept-Encoding':'gzip'
'id': 'some_random_number'
'User-Agent':'Firefox' 
'signature':'some_random_number' 
'Connection':'Keep-Alive' 
'Content-Type':'application/x-www-form-urlencoded'
'charset':'utf-8'
'name':'random' 

这对我来说是个问题。我不知道该做什么。任何帮助非常感谢。我试过urllib库没有支持

1 个答案:

答案 0 :(得分:3)

扩展评论,这是一个非常非常简单的OrderedHeadersrequests可能会满意:

class OrderedHeaders(object):

    def __init__(self, *headers):
        self.headers = headers

    def items(self):
        return iter(self.headers)


oh = OrderedHeaders(('Accept-Charset', 'Foo'), ('Bar', 'Foobar'))

for k, v in oh.items():
    print("%s:%s" % (k, v))

这是一个更详细的示例,它使用topological sorting来确定必须在其他标头之前给出哪些标头。它需要更多的代码,但你可以清楚地说明你的标题必须具有的排序,并像之后的任何其他字典一样使用该类。

import sys
import toposort

class OrderedHeaders(dict):
    # The precedence of headers is determined once. In this example, 
    # 'Accept-Encoding' must be sorted behind 'User-Agent'
    # (if defined) and 'version' must be sorted behind both
    # 'Accept-Encoding' and 'Connection' (if defined).
    PRECEDENCE = toposort.toposort_flatten({'Accept-Encoding': {'User-Agent'},
                                            'version': {'Accept-Encoding',
                                                        'Connection'}})

    def items(self):
        s = []
        for k, v in dict.items(self):
            try:
                prec = self.PRECEDENCE.index(k)
            except ValueError:
                # no defined sort for this header, so we put it behind
                # any other sorted header
                prec = sys.maxsize
            s.append((prec, k, v))
        return ((k, v) for prec, k, v in sorted(s))

# Initialize like a dict
headers = OrderedHeaders(name='random', Connection='Keep-Alive')
...
# Setting more values
headers['Accept-Encoding'] = 'gzip'
headers['version'] = '0.1'
headers['User-Agent'] = 'Firefox'
...
# Headers come out of '.items()' like they should
for k, v in headers.items():
    print("%s: %s" % (k, v))

打印

Connection: Keep-Alive
User-Agent: Firefox
Accept-Encoding: gzip
version: 0.1
name: random

因为Connection需要在version之前出现,User-Agent需要在Accept-Encoding之前出现,Accept-Encoding需要在versionname之前出现{1}}没有排序,因此放在最后。

您可以按照您想要的任何顺序在OrderedHeaders上设置值,在.items()中完成排序。但是,您可以确定始终可以进行声音排序:如果您犯了错误并定义了循环依赖(例如'版本'>'用户代理'>&#39 ;版本'),您将在"编译时"得到toposort.CircularDependencyError