How to properly handle an aborted HTTP request in Django
Whenever a lengthy HTTP requests is aborted by the client (e.g. Browser is closed) Django views seem to raise a IOError exception.
What's the proper way to detect such an aborted request if I just want to ignore them? Just 开发者_如何学Gocatching IOError seems too wide.. might accidentally ignore other IO problems.
In django 1.3 and up, you can use a logging filter class to suppress the exceptions which you aren't interested in. Here's the logging filter class I'm using to narrowly suppress IOError exceptions raised from _get_raw_post_data()
:
import sys, traceback
class _SuppressUnreadablePost(object):
def filter(self, record):
_, exception, tb = sys.exc_info()
if isinstance(exception, IOError):
for _, _, function, _ in traceback.extract_tb(tb):
if function == '_get_raw_post_data':
return False
return True
In Django 1.4, you will be able to do away with most of the complexity and suppress the new exception class UnreadablePostError
. (See this patch).
The best way to do it would be to use a custom middleware class that implements process_exception()
to return a custom HTTP response, say a rendered errors/request_aborted.html
template, if an IOException
is caught.
Raven now connects itself to the got_request_exception() signal to catch unhandled exceptions, bypassing the logging system entirely, so the solution proposed by dlowe does not work anymore.
However raven looks for a skip_sentry
attribute on the exception instance, so you can use a middleware to set it on the errors you want to ignore:
import sys
import traceback
class FilterPostErrorsMiddleware(object):
"""
A middleware that prevents unreadable POST errors to reach Sentry.
"""
def process_exception(self, request, exception):
if isinstance(exception, IOError):
tb = sys.exc_info()[2]
for _, _, function, _ in traceback.extract_tb(tb):
if function == '_get_raw_post_data':
exception.skip_sentry = True
break
Note: you have to use a recent version of raven (e.g. 1.8.4), as previous versions mistakenly checked for the skip_sentry
attribute on the exception type rather than instance.
If you want to ignore the IOError
, then just let it be. You don't need to catch it. If you absolutely must catch it, you can do what @Filip Dupanović suggested, and maybe return a django.http.HttpResponseServerError
to set the response code to 500
.
精彩评论