web-dev-qa-db-ja.com

Djangoデバッグモードでパイプが壊れている

Nginxの背後のリモートサーバーにDjango 1.3があります。

Apache + mod_wsgiでDjangoを実行すると、Apacheログファイルのエラーを見ることができます。大丈夫ですが、コンソールに表示したいと思います。

Django独自の開発サーバーを実行すると、DEBUG = Falseの場合にのみコンソールのスタックトレースでエラーが発生します。DEBUGモードのコンソール出力では

Exception happened during processing of request from (..., ...)
Traceback (most recent call last):
  File "/usr/local/python/lib/python2.7/SocketServer.py", line 284, in _handle_request_noblock
    self.process_request(request, client_address)
  File "/usr/local/python/lib/python2.7/SocketServer.py", line 310, in process_request
    self.finish_request(request, client_address)
  File "/usr/local/python/lib/python2.7/SocketServer.py", line 323, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "/usr/local/python/lib/python2.7/site-packages/Django/core/servers/basehttp.py", line 570, in __init__
    BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
  File "/usr/local/python/lib/python2.7/SocketServer.py", line 641, in __init__
    self.finish()
  File "/usr/local/python/lib/python2.7/SocketServer.py", line 694, in finish
    self.wfile.flush()
  File "/usr/local/python/lib/python2.7/socket.py", line 301, in flush
    self._sock.sendall(view[write_offset:write_offset+buffer_size])
error: [Errno 32] Broken pipe

理由を知りたいですか?なぜDjangoは名前のない例外を出力するだけですか?なぜDEBUG変数に依存するのですか?.

このエラーは、リクエストオブジェクトへのアクセス権がない場合、ほとんどの場合ビューの外側で発生します。そのため、ミドルウェアやロギングハンドラーでそれをキャッチすることはできません。

更新。 Djangoサーバーに直接リクエストすると、パイプが壊れることはありません。Nginxプロキシdjangoで問題が発生する可能性があります。

48
San4ez

Nginxディレクティブproxy_intercept_errors off;(デフォルトで無効)は必要なものです

8
San4ez

これは実際にはあなたのサイトの問題ではなく、Django devserver:これを参照してください Djangoチケット 。既知のエラーであり、修正されません。

そのチケットのコメントには、非常に明確な説明が記載されています。

多くの情報筋によると、「壊れたパイプ」は通常のブラウザの癖です。たとえば、ブラウザはソケットから読み取り、読み取り中のイメージが明らかに変更されていないと判断します。これでブラウザは、これ以上のデータを必要としないため、(強制的に)接続を閉じます。このソケットのもう一方の端(python runserver)は、クライアントに「ソケットパイプを壊した」ことをプログラムに伝えるソケット例外を発生させます。

55
jro

Nginxディレクティブ(チェックされた答え)は私には機能しませんでしたが、Igor KatsonとMichael_Scharfのモンキーパッチを組み合わせた場合は機能しました:

def patch_broken_pipe_error():
    """Monkey Patch BaseServer.handle_error to not write
    a stacktrace to stderr on broken pipe.
    http://stackoverflow.com/a/22618740/362702"""
    import sys
    from SocketServer import BaseServer
    from wsgiref import handlers

    handle_error = BaseServer.handle_error
    log_exception = handlers.BaseHandler.log_exception

    def is_broken_pipe_error():
        type, err, tb = sys.exc_info()
        return repr(err) == "error(32, 'Broken pipe')"

    def my_handle_error(self, request, client_address):
        if not is_broken_pipe_error():
            handle_error(self, request, client_address)

    def my_log_exception(self, exc_info):
        if not is_broken_pipe_error():
            log_exception(self, exc_info)

    BaseServer.handle_error = my_handle_error
    handlers.BaseHandler.log_exception = my_log_exception

patch_broken_pipe_error()
6
Rick Mohr

メッセージをstderrに出力しないようにする方法を次に示します。ただ monkey patch the BaseServer.handle_error 関数。これは私がそれを行う方法です:

def patch_broken_pipe_error():
    """Monkey Patch BaseServer.handle_error to not write
    a stacktrace to stderr on broken pipe.
    https://stackoverflow.com/a/7913160"""
    import sys
    from SocketServer import BaseServer

    handle_error = BaseServer.handle_error

    def my_handle_error(self, request, client_address):
        type, err, tb = sys.exc_info()
        # there might be better ways to detect the specific erro
        if repr(err) == "error(32, 'Broken pipe')":
            # you may ignore it...
            logging.getLogger('mylog').warn(err)
        else:
            handle_error(self, request, client_address)

    BaseServer.handle_error = my_handle_error


patch_broken_pipe_error()
4
Michael_Scharf

私はこれを取り除くことができました

proxy_buffering off;

これにより、プロキシされたサーバーの応答バッファリングが停止します。これにより、クライアントが非常に遅い接続にある場合、バックエンドアプリケーションが長時間ロックされるという別の問題が発生します。

特定の要求に対して条件付きにするには、応答ヘッダーでX-Accel-Buffering = noを使用します。

2
rane

「./manage.py runserver」を使用したり、LiveServerTestCaseテストを実行したりすると、この厄介なエラーを取り除く、簡単で汚いモンキーパッチ(有用なエラーを抑制するかどうかわかりません)を思い付きました。

必要な場所にコードのどこかに挿入するだけです:

# Monkeypatch python not to print "Broken Pipe" errors to stdout.
import SocketServer
from wsgiref import handlers
SocketServer.BaseServer.handle_error = lambda *args, **kwargs: None
handlers.BaseHandler.log_exception = lambda *args, **kwargs: None
2
Igor Katson

それを私が直した。ページ内でアンカータグなどのリンクを使用する場合、「パイプの破損」問題に直面する必要があります。リンクタグhref = '#'内で使用するだけです。 href属性を空白のままにしないでください。そのタイプのエラーを回避します。

0

tilelite を使用しているときにもこの問題に遭遇しました。実際には、Pythonの既知のバグと現在修正されたバグが原因です。この問題は、次のパッチを適用することで解決できます。

http://bugs.python.org/issue14574

それ以外の場合は、最新のPythonビルドの1つをダウンロードできます。

0
Jason Huntley