Django Broken pipe в режиме отладки

У меня есть django 1.3 на удаленном сервере за Nginx.

Если я запускаю django с apache + mod_wsgi, я могу наблюдать ошибки в файлах журнала apache. Это нормально, но я хотел бы иметь консоль.

Если я запускаю собственный сервер разработки django, я получаю ошибки с помощью stacktrace в консоли только тогда, когда 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.

Эти ошибки возникают в основном из внешних представлений, когда у меня нет доступа к объекту запроса. Поэтому я не могу поймать его в промежуточном программном обеспечении или с помощью обработчика ведения журнала.

UPDATE. Я заметил, что если я запрошу сервер django напрямую, я никогда не получаю Broken pipe. Так может возникнуть проблема, когда Nginx proxy django?

Ответ 1

Директива Nginx proxy_intercept_errors off; (по умолчанию отключена) - это то, что мне нужно

Ответ 2

Это не проблема с вашим сайтом, больше с Django devserver: см. этот Django ticket. Чтобы сказать это прямо, просто игнорируйте его, поскольку это известная ошибка, и не будет исправлена.

В комментариях к билету дается достаточно четкое объяснение:

Согласно многим источникам, "Broken Pipe" - обычная причуда браузера. Например, браузер читает из сокета, а затем решает, что изображение, которое оно читает, по-видимому, не изменилось. Браузер теперь (принудительно) закрывает соединение, потому что ему не нужно больше данных. Другой конец этого сокета (python runningerver) теперь вызывает исключение сокета, указывающее программе, что клиент "сломал трубку сокета".

Ответ 3

Директива nginx (проверенный ответ) не сработала для меня, но комбинация патчей обезьян от Игоря Катсона и Майкла_Шарфа сделала:

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()

Ответ 4

Вот способ предотвращения печати сообщения на stderr. Просто патч обезьяны 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()

Ответ 5

Я смог избавиться от этого

proxy_buffering off;

Это останавливает буферизацию ответа прокси-сервера. Это приводит к тому, что другие проблемы, связанные с тем, что серверное приложение блокируется долго, если клиент находится на чрезвычайно медленном соединении.

Чтобы сделать это условным для конкретных запросов, используйте X-Accel-Buffering = no в заголовке ответа.

Ответ 6

Я придумал быстрый и грязный патч обезьяны (я не знаю, удовлетворяет ли он какие-либо полезные ошибки), который избавляется от этой досадной ошибки при использовании "./manage.py runningerver" или запускает тесты 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

Ответ 7

Я столкнулся с этой проблемой, используя tilelite. Это фактически вызвано известной, а теперь исправленной ошибкой в ​​python. Вы можете решить эту проблему, применив следующий патч:

http://bugs.python.org/issue14574

В противном случае вы можете загрузить одну из последних версий python.

Ответ 8

Я исправил его. Если вы используете ссылки, т.е. Тег привязки, внутри страницы, вам придется столкнуться с проблемой "Borken Pipe". Просто используйте внутри тега ссылки href= '#'. Не оставляйте атрибут href пустым. Это позволит избежать такого типа ошибок.