Django视图函数捕捉异常
前言
不存在没有BUG的代码,也不存在不会出现异常的视图函数。当Django视图函数中的代码出现异常时,访问这个URL的用户就会收到状态码为500 Internal Server Error
的HTTP 响应。如何捕捉视图函数里出现的异常,这是本篇文章要讨论的问题。
注:本文所使用的运行环境为
uWSGI 2.0.18
+Python3.6
+Django 2.2
在uWSGI的日志中显示Traceback
这种方法算是一种比较消极的异常捕捉方式——仅将Traceback
异常信息记录在uWSGI的日志中,不做进一步处理。日志可以用于日后分析,但用户收到的仍然是500 Internal Server Error
响应。而这种捕捉方式也是默认启用的,只要所使用的Django版本高于或等于1.9
就行。例子如下:
1 |
|
配置好路由和视图函数并用uWSGI
启动应用后,访问/index
页面就会触发ZeroDivisionError
异常,该异常的Traceback信息也会输出至uWSGI
的日志中,效果如下:
1 |
|
用函数装饰器捕捉异常
Django中的视图函数只是一个普通的函数(废话),这就意味着我们可以用一个能够捕捉异常的函数装饰器来包裹这个视图函数,例子如下:
1 |
|
在例子第18行~第19行,我用catch_exc
这个装饰器包裹了index
这个视图函数。而在catch_exc
这个装饰器内部,我用except Exception
语句捕捉了index
函数所有可能出现的异常。然后,我们就可以按照需要来进行各种操作了,比如:
- 用
traceback.format_exc()
获取详细的Traceback
信息; - 将错误信息输出至日志;
- 通知某人;
等等等等。对异常的处理完成后,我们既可以通过raise
语句让用户仍然收到500 Internal Server Error
响应,也可以像上面的例子中返回一个关于异常信息的200 OK
响应,还可以渲染一个提示HTML页面返回给用户。总之,Everything is under control.
用Django中间件捕捉异常
函数装饰器很好用,但装饰器只能针对单个视图函数。有没有一种应用于所有视图函数之上的异常捕捉方法?有的,这就是Django的中间件。和我上一篇文章(使用中间件对视图函数进行性能分析)不同的是,那篇文章里所使用的中间件hook为process_request&process_response
,而这里使用中间件hook为process_exception
,因为前者无法捕捉异常。
1 |
|
和上一节的装饰器类似,当视图函数出现异常时,Django就会遍历所有中间件的process_exception
hook,包括例子里的。在这个process_exception
方法里,我们同样可以完成上一节提到的各种操作,操作完成后可以通过return None
语句让用户仍然收到500 Internal Server Error
响应,也可以像上面的例子中返回一个关于异常信息的200 OK
响应……这里就不再重复了。
后记
其实在非DEBUG模式(settings.py
里DEBUG = False
)下,Django可以将视图函数里出现的异常信息以电子邮件的形式发送给ADMINS
里配置的邮箱地址。这个功能需要配置邮箱参数、LOGGING,这里就不详细展开了,有兴趣的话可以查看Django2.2官方文档(Error reporting)或搜索相关教程。