英文原文地址:http://flask.pocoo.org/docs/1.0/errorhandling/
若有翻译错误或者不尽人意之处,请指出,谢谢~
(在版本0.3新增。)
应用程序失败,服务器失败。你迟早会在生产中看到一个异常。即使你的代码100%正确,但你偶尔还是能看到异常,这是为什么呢?因为其他相关的东西可能会失败。在某些情况下,完美的代码依然能导致服务器错误:
● 客户端提前终止了请求,但是应用程序依旧对传来的数据进行读取。
● 数据库服务器超载,因此不能处理查询请求。
● 文件系统已经满了。
● 一个硬盘崩溃。
● 一个后台服务器超载。
● 你正在使用的一个库发生了一个错误。
● 网络连接到另一个系统失败。
这里只是列举了一小部分你可能面临的问题。因此我们要怎么处理这一系列的问题呢?默认情况下,如果你的应用程序在生产模式下运行,Flask会为你显示一个非常简单的页面并且将异常记录到日志记录器(logger)中。
但你可以做的更多,我们将介绍一些更好的方法来处理错误。
1. 错误日志工具
如果有足够多的用户遇到错误,并且日志文件通常从不被查看,即使只发送关键的错误邮件,邮件也会被不断淹没。这也是为什么我们推荐使用Sentry来处理应用程序错误的原因。它是一个在GitHub上开源且可用的项目,并且它也提供了可以免费使用的托管版本。Sentry聚集了重复的错误,捕获了完整的堆栈跟踪和局部变量进行调试,并且根据新的错误或者预设的频率阈值向你发送邮件。
为了使用Sentry,你需要在raven客户端安装额外的flask依赖项:
$ pip install raven[flask]
接着在你的Flask应用中添加如下代码:
from raven.contrib.flask import Sentry sentry = Sentry(app, dsn='YOUR DSN HERE')
如果你正在使用工厂模式,你也可以随后进行初始化:
from raven.contrib.flask import Sentry sentry = Sentry(dsn='YOUR DSN HERE') def create_app(): app = Flask(__name__) sentry.init_app(app) ... return app
这里的YOUR_DSN_HERE的值需要替换为从Sentry安装获取到的DSN值。
随后的错误会自动向Sentry进行上报,你可以从Sentry接收到错误通知。
2. 错误处理程序
你可能希望当有错误发生的时候,向用户显示自定义的错误页面。通过注册错误处理程序可以完成你的期望。
一个错误处理程序是返回一个响应对象的正常视图方法,但它并不是注册为路由事件,而是注册为一个异常或者HTTP状态码,该代码在处理请求时被抛出。
2.1 注册
注册处理程序是使用errorhandler()对方法进行修饰。或者使用register_error_handler()在随后为一个方法进行注册。一定要记得在返回响应对象时要设置错误代码。
@app.errorhandler(werkzeug.exceptions.BadRequest) def handle_bad_request(e): return 'bad request!', 400 # or, without the decorator app.register_error_handler(400, handle_bad_request)
werkzeug.exceptions.HTTPException的子类像是BadRequest,在注册处理程序的时候,它们的HTTP代码是可互换的。(BadRequest.Code == 400)
非标准的HTTP代码不能通过代码方式进行注册,因为它们在Werkzeug中是未知的。相反,定义一个HTTPException的子类,且为这个子类定义一个适当的代码,就可以注册并抛出这个异常类了。
class InsufficientStorage(werkzeug.exceptions.HTTPException): code = 507 description = 'Not enough storage space.' app.register_error_handler(InsufficientStorage, handle_507) raise InsufficientStorage()
处理程序可以注册为任何异常类,不仅仅是HTTPException的派生类或者HTTP状态码。处理程序可以被注册为一个指定的类,或者是一个父类的所有子类。
2.2 处理
当Flask在处理一个请求时捕获到了一个异常,它首先将查找这个错误代码。如果这个错误代码并没有注册处理事件,那么它将继续在类层次中进行查找;一直到选择最特定的处理程序。如果没有注册处理程序,HTTPException子类会显示一个关于其代码的通用消息,而其他异常则被转换成一个通用的500代码,表示内部服务器错误。
举个栗子,如果一个ConnectionRefusedError实例被抛出,并且一个处理程序被注册为ConnectionError和ConnectionRefusedError,那么异常实例就会调用更为具体的ConnectionRefusedError处理程序来生成响应。
假设一个蓝图正在处理引发异常的请求,那么在蓝图上注册的处理程序优先于在应用程序上注册的全局处理程序。然而,蓝图不能处理404路由错误,因为404发生在蓝图可以被确定之前的路由级别。
注意,版本0.11的变更:处理程序的优先级取决于它们注册的异常类的特定性,而不是它们的注册顺序。
3. 日志
参见Logging获取如何记录异常,比如以邮件的形式记录这些异常并发送给管理员。