10

httpチャンク転送エンコーディングの処理に問題があります。

私が使用しているもの:

  • apache。
  • mod_wsgiプラグイン。
  • django。

djangoは、content-lengthヘッダーフィールドを持つ通常のhttpリクエストのみを処理できますが、TE(Transfer-Encoding)、チャンク、またはgzipの処理に関しては、空の結果を返します。

私は2つのアプローチを考えています:

  1. django.wsgipythonファイルに変更を加える
  2. ミドルウェアのPythonファイルをdjangoに追加して、チャンク化されたhttpリクエストをインターセプトし、content-lengthヘッダーフィールドを持つrequelar httpリクエストに変換してから、djangoに渡します。

誰でも上記の2つのオプションのいずれかを手伝うことができます(もちろん、より多くのオプションが大歓迎です)

ありがとう!


これは、グラハムの最初の回答の後の私の質問の拡張です。

まず第一に、あなたの迅速な対応に感謝します。使用しているクライアントはAxisです。これは、当社と通信する他社のシステムの一部です。私はWSGIChunkedRequest On設定しました。また、次のようにwsgiラッパーにいくつかの変更を加えました。

def application(environ, start_response):

    if environ.get("mod_wsgi.input_chunked") == "1":
        stream = environ["wsgi.input"]
        print stream
        print 'type: ', type(stream)
        length = 0
        for byte in stream:
            length+=1
        #print length    
        environ["CONTENT_LENGTH"] = len(stream.read(length))

    django_application = get_wsgi_application()
    return django_application(environ, start_response)

しかし、それは私にそれらのエラーを与えます(apacheのerror.logファイルから抽出されました):

[Sat Aug 25 17:26:07 2012] [error] <mod_wsgi.Input object at 0xb6c35390>
[Sat Aug 25 17:26:07 2012] [error] type:  <type 'mod_wsgi.Input'>
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx] mod_wsgi (pid=27210): Exception occurred processing WSGI script '/..../wsgi.py'.
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx] Traceback (most recent call last):
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx]   File "/..../wsgi.py", line 57, in application
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx]     for byte in stream:
[Sat Aug 25 17:26:08 2012] [error] [client xxxxxxxxxxxxx] IOError: request data read error

私は何を間違っているのですか?!

4

2 に答える 2

14

これは Django の問題ではありません。これは、WSGI 仕様がリクエストに CONTENT_LENGTH 値を要求することによって、チャンク化されたリクエスト コンテンツの使用を禁止している限りにおいて、WSGI 仕様自体の制限です。

mod_wsgi を使用する場合、チャンクされたリクエスト コンテンツの非標準サポートを有効にするためのスイッチがありますが、これは、アプリケーションが WSGI に準拠していないことを意味します。さらに、Django では動作しないため、カスタム Web アプリケーションまたは WSGI ラッパーが必要になります。 .

チャンクされたリクエストコンテンツを許可する mod_wsgi のオプションは次のとおりです。

WSGIChunkedRequest On

WSGI ラッパーは wsgi.input.read() を呼び出してコンテンツ全体を取得し、それを使用して StringIO インスタンスを作成し、それを使用して wsgi.input を置き換え、ラップされたアプリケーションを呼び出す前に新しい CONTENT_LENGTH 値を実際の長さで Environment に追加する必要があります。

どれだけのデータが送信されているかがわからないため、これは危険であることに注意してください。

とにかく、チャンクされたリクエストコンテンツのみをサポートするどのクライアントを使用していますか?


更新 1

あなたのコードはさまざまな理由で壊れています。次のようなものを使用する必要があります。

import StringIO

django_application = get_wsgi_application()

def application(environ, start_response):

    if environ.get("mod_wsgi.input_chunked") == "1":
        stream = environ["wsgi.input"]
        data = stream.read()   
        environ["CONTENT_LENGTH"] = str(len(data))
        environ["wsgi.input"] = StringIO.StringIO(data)

    return django_application(environ, start_response)

これは、gzip されたリクエスト コンテンツには役立たないことに注意してください。コンテンツのエンコーディングがいつ圧縮データであったかを確認し、上記と同じことを行うには、追加のチェックが必要です。これは、データが Apache によって圧縮解除されると、コンテンツの長さが変化し、再計算する必要があるためです。

于 2012-08-23T12:21:27.143 に答える
3

これですべてがスムーズに機能します。問題はデーモンモードにありました。チャンク化されたhttpトラフィックでは機能しないため、GrahamDumpletonによるとmod_wsgi4にある可能性があります。したがって、この問題が発生した場合は、mod_wsgiを埋め込みモードに切り替えてください。

wsgiラッパーのGrahamのコードの変更として、環境変数にバッファリングされたストリームを読み取ることができる2つのオプションがあります。

最初の1つ:

try:
    while True:
        data+= stream.next()
except:
    print 'Done with reading the stream ...'

二つ目:

try:
   data+= stream.read()
except:
   print 'Done with reading the stream ...' 

最初のコードスタブはデーモンモードでバッファを読み取ることができましたが、どこかで停止し、プログラムは動作を継続しませんでした(これは、うまく機能することを期待していたので、少し混乱しました)が、他のコードスタブはクラッシュしましたIOErrorがあり、埋め込みモードでのみ機能します。

さらにもう1つ、3.3から3.4にアップグレードしても問題は解決しなかったため、埋め込みモードに切り替える必要があります。

これらは私の結果と観察です。コメント、追加、訂正がありましたら、お気軽にどうぞ。

ありがとう!

于 2012-08-26T17:00:28.997 に答える