2017-07-01 4 views
5

私は現在Python 2.7リクエストライブラリを使用していますが、順序付けられたヘッダはサポートされていません。私はポストのために順序づけられたデータを置くことができ、(順序付けられた辞書のように)得ることができますが、単にヘッダーのためのサポートがありません。私はHTTPプロトコルRFCを知っていますが、ヘッダーの順序は重要ではないことを示していますが、問題は、ヘッダが整っていなければ、私が実装しているサードパーティのサービスが動作しないということです。私はこれを知っています。私は他の言語で注文されたヘッダリクエストを実装しています。それはJavaのように動作しますし、はい、私はそれを100%確信しています。なぜなら、これがリクエスト間の唯一の違いであることを確認するためです。 。しかし、私は既にPythonで5,000以上の行を持っていますので、このような問題のためにこのような痛みを伴う決定があります。Python - Ordersed Headers HTTPリクエスト

私が考えている唯一の解決策は、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' 
を送信されたリクエストヘッダの順序

これは私には問題です。私はこの時点で何をすべきか分かりません。どんな助けでも大歓迎です。

ここ
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を使用して、より詳細な例である:私はここrequestsはと幸せかもしれない非常に、非常に単純なOrderedHeadersことで、コメントを拡張し、ライブラリurllibはノーサポート

+0

dictを注文しますか? –

+1

いいえ、ordered dictを使用すると、要求ライブラリはitems()メソッドを使用してヘッダーを解析し、ordered dictのサポートはないため、要求ライブラリに対して.items()例外が発生します。それは私が別のstackoverflowの質問で読んだものからいくつかの非常に古い要求のバージョンで動作するために使用されていました。 –

+1

返されるヘッダの順序を制御するカスタム '.items()'を持つカスタムのdict-likeオブジェクトを 'requests'に渡すことはできますか? '要求'がその順序を保つなら、あなたは良い考えである – user2722968

答えて

3

を試していません他のヘッダーの前に指定する必要があります。もう少しコードを追加する必要がありますが、ヘッダを一度ソートする必要があるかどうかを明確に述べ、後で他のdictと同じように使用することができます。

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 

versionUser-AgentニーズがAccept-Encoding前に来るように前Connectionニーズが来ているので、Accept-Encodingversionnameは何の並べ替えを持っていないの前に来る必要があり、最後に入れて、そのためです。

OrderedHeadersに値を設定することができます。並べ替えは.items()で行います。しかし、あなたは間違いを犯して循環依存性を定義すると(例えば、 'version'> 'User-Agent'> 'version')、コンパイル時にtoposort.CircularDependencyErrorを得るでしょう。時間"。

+0

私が実行したテストは、ソリューションが動作します!私はあなたの答えに本当にうれしくて幸せです。それ以上問題が発生したかどうかは分かりません。しかし、これは非常に簡単な解決策であり、人生の節約にもなります。 すべてのテストで確認した後、私は正しいとマークします。 –

+0

ここで取り上げる教訓は、Pythonではオブジェクトが何をしているのか気にしているのか、オブジェクトは何かを気にすることではありません。 '要求'は '.items()'の 'dict'のように動作するオブジェクトを期待しています。実際の' dict'を渡すとそれが得られます。ただし、オブジェクトが動作している限り、他のものを渡すことはできます。 – user2722968

関連する問題