2017-07-01 79 views
5

我目前使用python 2.7請求庫,並且不支持有序標題。我可以把有序的數據發佈和獲取(像一個有序的字典),但是根本不支持頭文件。甚至沒有在python 3Python - 有序標題HTTP請求

我知道HTTP協議的RFC,表明標題的順序是微不足道的,但問題是,我正在實施的第三方服務不起作用,除非標題是按順序。我知道這是因爲我已經在其他語言中實現了有序的頭部請求,並且它可以工作(如java),並且我確信100%是這樣,因爲我檢查了burp和wireshark以確保這是請求之間的唯一區別。但是我已經有了超過5000行python,所以在那裏遷移是一個如此痛苦的決定,因爲這樣的問題。

我唯一想到的解決方案是在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庫不支持

+0

會下令字典工作? –

+1

不,使用有序的詞典爲請求庫提供.items()異常,因爲請求庫使用items()方法解析頭並且沒有對有序字典的支持。它曾經在一些非常舊的請求版本中工作,這是我在另一個stackoverflow問題上閱讀的版本。 –

+1

你可以傳遞一個自定義類似dict的對象給'request',它有一個自定義的'.items()',它控制返回的頭文件的順序嗎?如果'request'保持這個順序,那麼你最好去 – user2722968

回答

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需求來之前versionUser-Agent需要Accept-Encoding來之前,Accept-Encoding需要來之前versionname沒有排序,併爲此把最後。

您可以以任何您想要的順序在OrderedHeaders上設置值,排序在.items()中完成。但是你可以確定一個聲音的排序總是可能的:如果你犯了一個錯誤並且定義了一個循環依賴(例如'版本'>'用戶代理'>'版本'),你會得到一個toposort.CircularDependencyError在「時間」。

+0

我運行的測試,解決方案工作!我對你的回答感到非常高興和高興。我不知道是否還有其他問題出現。但這是一個非常簡單的解決方案和一個救生員。 我確認所有測試後,我會標記爲正確。 –

+0

帶回家的教訓是記住,在Python中,人們只關心對象的功能,而不關心對象是什麼。 'request'需要一個在'.items()'上像'dict'一樣的對象,如果你傳遞了一個真正的'dict',那就是你所得到的。但是,只要對象表現正常,您就可以傳遞任何其他內容。 – user2722968