Django在debugging模式下损坏的pipe道

我在Nginx后面的远程服务器上安装了django 1.3。

如果我用apache + mod_wsgi运行django,我可以在apache日志文件中看到错误。 没关系,但我想在控制台。

如果我运行django自己的开发服务器,只有在DEBUG = False时,才会在控制台中得到堆栈跟踪的错误。 在debugging模式控制台输出

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只输出无名的exception? 为什么它依赖于DEBUGvariables。

当我无法访问请求对象时,这种错误大多出现在视图外部。 所以我不能在中间件或使用日志处理程序捕捉它。

UPDATE。 我注意到,如果我直接请求Django服务器,我从来没有得到坏的pipe道。 那么Nginx的代理django会出现这个问题吗?

这对于您的网站来说并不是什么问题,更多的是使用Django devserver:查看这个Django票据 。 说穿了,只是忽略它,因为这是一个已知的错误,不会被修复。

在那张票的评论中给出了一个非常明确的解释:

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

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

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

这是一种防止将信息打印到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() 

我能够摆脱这一点

proxy_bufferingclosures;

这会停止代理服务器的响应缓冲。 这导致后端应用程序的其他问题被locking很长时间,如果客户端在一个非常缓慢的连接。

为了使特定请求有条件,在响应头中使用X-Accel-Buffering = no

我想出了一个快速和肮脏的猴子补丁(我不知道它是否抑制了任何有用的错误),当使用“./manage.py runserver”或运行LiveServerTestCasetesting时,摆脱了这个恼人的错误。

只要将它插入代码中的任何地方,你需要的地方:

 # 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 

我也遇到这个问题,同时使用tilelite 。 这实际上是由python中的一个已知的,现在修复的bug引起的。 您可以通过应用以下修补程序来解决此问题:

http://bugs.python.org/issue14574

否则,你可以下载一个更新的Python版本。

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