【问题标题】:Django Broken pipe in Debug mode调试模式下的Django Broken pipe
【发布时间】:2011-12-16 07:03:55
【问题描述】:

我在 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 服务器请求,我永远不会得到 Broken pipe。那么Nginx代理django时可能会出现问题吗?

【问题讨论】:

  • 我在实时服务器上没有遇到过这个问题,但是在我本地计算机上的 django dev 服务器上时不时会出现这个问题。我也无法解决这个问题跨度>
  • 在 django 发送响应之前可能只是 NGINX 超时。你的 nginx.conf 文件中设置的“proxy_read_timeout”是什么?

标签: django broken-pipe


【解决方案1】:

这不是您网站的真正问题,更多的是 Django 开发服务器:请参阅Django ticket。说白了,直接忽略,因为是已知错误,不会修复。

在那张票的cmets中给出了非常清楚的解释:

根据许多消息来源,“Broken Pipe”是一个正常的浏览器怪癖。例如,浏览器从套接字读取,然后确定它正在读取的图像显然没有改变。浏览器现在(强制)关闭连接,因为它不需要更多数据。这个套接字的另一端(python runserver)现在引发一个套接字异常,告诉程序客户端“破坏了套接字管道”。

【讨论】:

  • 谢谢。我以前看过那张旧票。我刚刚更新了问题。
【解决方案2】:

Nginx 指令proxy_intercept_errors off;(默认禁用)是我需要的

【讨论】:

  • 嗨 San4ez,正如您所说,默认情况下这似乎是禁用的。明确禁用此功能如何解决您的问题? (我可能有一个相关的问题......)
  • 我不太明白你的问题。想象一下,nginx 代理向 django 上游请求并获得一些错误状态(400 或更高)。如果proxy_intercept_errors 被禁用,nginx 会像来自 django 一样响应错误页面。否则 nginx 停止读取 django 响应并发送到用户自定义错误页面。 Django 服务器(或任何其他)抛出客户端不读取套接字的错误 - 管道损坏
  • 明白了;实际上这对我有用。这很奇怪,因为如果 proxy_intercept_errors 默认关闭,显式关闭它应该没有效果。见wiki.nginx.org/HttpProxyModule#proxy_intercept_errors
  • 是的,当然。但是我有 nginx 配置,其中有人启用了此选项
  • 对。那是有道理的。奇怪的是,它也对我有用,所以我猜该密钥必须在某些构建的某个文件中生成。
【解决方案3】:

我能够通过

摆脱这个

proxy_buffering 关闭;

这会停止代理服务器的响应缓冲。如果客户端的连接速度极慢,这会导致后端应用程序长时间锁定的其他问题。

要使其对特定请求有条件,请在响应标头中使用 X-Accel-Buffering=no

【讨论】:

    【解决方案4】:

    我在使用tilelite 时也遇到了这个问题。它实际上是由 python 中的一个已知且现已修复的错误引起的。您可以通过应用以下补丁来解决此问题:

    http://bugs.python.org/issue14574

    否则,您可以下载最新版本的 python 之一。

    【讨论】:

      【解决方案5】:

      我想出了一个快速而肮脏的猴子补丁(我不知道它是否会抑制任何有用的错误),它可以在使用“./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
      

      【讨论】:

        【解决方案6】:

        我修好了。 如果您在页面内使用链接(即锚标记),则必须面对“Borken Pipe”问题。只需在链接标签内使用 href='#'。不要将 href 属性留空。它将避免这种类型的错误。

        【讨论】:

          【解决方案7】:

          这是一种防止将消息打印到标准错误的方法。只需monkey patch 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()
          

          【讨论】:

            【解决方案8】:

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

            【讨论】:

            • 你也可以在你的 nginx 配置文件中启用 proxy_ignore_client_abort 选项。在这种情况下,如果客户端(网络浏览器)这样做,nginx 不会断开与后端的连接。
            • 此代码需要放在 settings.py - 使用 Django 1.5。
            【解决方案9】:

            在 Django 3.2+ 中,“错误”是由 logging 报告的 INFO,类似于:

            INFO - Broken pipe from ('127.0.0.1', 59895)
            

            @igor-katson 有一个快速而肮脏的猴子补丁。更新到 3.2+ 可以是:

            # Suppress broken pipe errors
            from django.core.servers.basehttp import WSGIServer
            WSGIServer.handle_error = lambda *args, **kwargs: None
            

            如果您在settings.py 中有条件检查是否处于开发(运行服务器)模式,您可以将这段代码放在那里。它会压制那个烦人的日志条目。

            请记住,WSGIServer.handle_error 也会报告非套接字错误。如果您有其他连接问题需要调试,这可能会妨碍您。

            【讨论】:

              【解决方案10】:

              当我删除“urls.py”路径中的“/”时,我的 BrokenPipe 错误消失了

              urlpatterns = [
                  path('', views.index)
              ]
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-04-09
                • 2020-01-24
                • 2011-07-07
                • 2016-10-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多