任何异常的全局错误处理程序
Global error handler for any exception
有没有办法添加全局错误处理程序,我可以在其中将响应更改为通用 JSON 响应?
我无法使用 got_request_exception
信号,因为不允许修改响应 (http://flask.pocoo.org/docs/0.10/signals/)。
In contrast all signal handlers are executed in undefined order and do not modify any data.
我宁愿不包装 app.handle_exception
函数,因为它感觉像是内部 API。我想我在寻找类似的东西:
@app.errorhandler()
def handle_global_error(e):
return "Global error"
请注意 errorhandler
不带任何参数,这意味着它将捕获所有 exceptions/status 没有附加特定错误处理程序的代码。我知道我可以使用 errorhandler(500)
或 errorhandler(Exception)
来捕获异常,但是如果我使用 abort(409)
,它仍然会 return 一个 HTML 响应。
您可以使用 @app.errorhandler(Exception)
:
Demo(HTTPException检查确保状态码被保留):
from flask import Flask, abort, jsonify
from werkzeug.exceptions import HTTPException
app = Flask('test')
@app.errorhandler(Exception)
def handle_error(e):
code = 500
if isinstance(e, HTTPException):
code = e.code
return jsonify(error=str(e)), code
@app.route('/')
def index():
abort(409)
app.run(port=1234)
输出:
$ http get http://127.0.0.1:1234/
HTTP/1.0 409 CONFLICT
Content-Length: 31
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:54 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "409: Conflict"
}
$ http get http://127.0.0.1:1234/notfound
HTTP/1.0 404 NOT FOUND
Content-Length: 32
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:58 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "404: Not Found"
}
如果您还想覆盖来自 Flask 的默认 HTML 异常(以便它们也 return JSON),请在 app.run
之前添加以下内容:
from werkzeug.exceptions import default_exceptions
for ex in default_exceptions:
app.register_error_handler(ex, handle_error)
对于较旧的 Flask 版本(<=0.10.1,即目前任何 non-git/master 版本),将以下代码添加到您的应用程序以显式注册 HTTP 错误:
from werkzeug import HTTP_STATUS_CODES
for code in HTTP_STATUS_CODES:
app.register_error_handler(code, handle_error)
远非优雅,但下面的工作将 HTTPException
的所有子类绑定到一个错误处理程序:
from flask import jsonify
from werkzeug.exceptions import HTTPException
def handle_error(error):
code = 500
if isinstance(error, HTTPException):
code = error.code
return jsonify(error='error', code=code)
for cls in HTTPException.__subclasses__():
app.register_error_handler(cls, handle_error)
这是 Flask 0.12 兼容的,是一个很好的问题解决方案(它允许以 JSON 或任何其他格式呈现错误)
from functools import wraps
from flask import Flask, redirect, jsonify
app = Flask(__name__)
def get_http_exception_handler(app):
"""Overrides the default http exception handler to return JSON."""
handle_http_exception = app.handle_http_exception
@wraps(handle_http_exception)
def ret_val(exception):
exc = handle_http_exception(exception)
return jsonify({'code':exc.code, 'message':exc.description}), exc.code
return ret_val
# Override the HTTP exception handler.
app.handle_http_exception = get_http_exception_handler(app)
https://github.com/pallets/flask/issues/671#issuecomment-12746738
如果异常不起作用,您可以尝试 app.register_error_handler
(或以 non-decorator 的方式使用 app.errorhandler
)
在 Flask >=0.12 中实现这个的更简洁的方法是为每个 Werkzeug 异常显式注册处理程序:
from flask import jsonify
from werkzeug.exceptions import HTTPException, default_exceptions
app = Flask('test')
def handle_error(error):
code = 500
if isinstance(error, HTTPException):
code = error.code
return jsonify(error='error', code=code)
for exc in default_exceptions:
app.register_error_handler(exc, handle_error)
基于
Plain (non-HTML) error pages in REST api
我想 return json 完全不更改我的任何代码,所以我只是在我的代码顶部添加了以下内容
@app.errorhandler(500)
def error_500(exception):
return jsonify({"error": str(exception)}), 500, {'Content-Type': 'application/json'}
@app.errorhandler(400)
def error_400(exception):
return jsonify({"error": str(exception)}), 400, {'Content-Type': 'application/json'}
可以为非常通用的基础 class 注册错误处理程序,例如 HTTPException
甚至 Exception
。但是,请注意,这些捕获的数量会超出您的预期。
例如,HTTPException
的错误处理程序可能有助于将默认 HTML 错误页面转换为 JSON。但是,此处理程序将触发您不直接导致的事情,例如路由期间的 404 和 405 错误。请务必仔细制作您的处理程序,以免丢失有关 HTTP 错误的信息。
from flask import Flask, abort, jsonify, json
from werkzeug.exceptions import HTTPException
app = Flask('test')
app.config['JSON_SORT_KEYS'] = False
@app.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"error": {
"code": e.code,
"name": e.name,
"description": e.description,
}
})
print(response.data)
response.content_type = "application/json"
return response
@app.route('/')
def index():
abort(409)
@app.route('/aloha')
def aloha():
abort(400, "I'm not in the mood to talk!")
app.run(port=1234)
输出:
Exception
的错误处理程序对于更改向用户显示所有错误(甚至是未处理的错误)的方式似乎很有用。但是,这类似于执行 except Exception
:在 Python 中,它将捕获 所有 否则未处理的错误,包括所有 HTTP 状态代码。
在大多数情况下,为更具体的异常注册处理程序会更安全。由于 HTTPException
个实例是有效的 WSGI 响应,您也可以直接传递它们。
from werkzeug.exceptions import HTTPException
@app.errorhandler(Exception)
def handle_exception(e):
# pass through HTTP errors
if isinstance(e, HTTPException):
return e
# now you're handling non-HTTP exceptions only
return render_template("500_generic.html", e=e), 500
错误处理程序仍然遵循异常 class 层次结构。如果您同时为 HTTPException
和 Exception
注册处理程序,Exception
处理程序将不会处理 HTTPException
subclasses,因为 HTTPException
处理程序是更具体。
有没有办法添加全局错误处理程序,我可以在其中将响应更改为通用 JSON 响应?
我无法使用 got_request_exception
信号,因为不允许修改响应 (http://flask.pocoo.org/docs/0.10/signals/)。
In contrast all signal handlers are executed in undefined order and do not modify any data.
我宁愿不包装 app.handle_exception
函数,因为它感觉像是内部 API。我想我在寻找类似的东西:
@app.errorhandler()
def handle_global_error(e):
return "Global error"
请注意 errorhandler
不带任何参数,这意味着它将捕获所有 exceptions/status 没有附加特定错误处理程序的代码。我知道我可以使用 errorhandler(500)
或 errorhandler(Exception)
来捕获异常,但是如果我使用 abort(409)
,它仍然会 return 一个 HTML 响应。
您可以使用 @app.errorhandler(Exception)
:
Demo(HTTPException检查确保状态码被保留):
from flask import Flask, abort, jsonify
from werkzeug.exceptions import HTTPException
app = Flask('test')
@app.errorhandler(Exception)
def handle_error(e):
code = 500
if isinstance(e, HTTPException):
code = e.code
return jsonify(error=str(e)), code
@app.route('/')
def index():
abort(409)
app.run(port=1234)
输出:
$ http get http://127.0.0.1:1234/
HTTP/1.0 409 CONFLICT
Content-Length: 31
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:54 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "409: Conflict"
}
$ http get http://127.0.0.1:1234/notfound
HTTP/1.0 404 NOT FOUND
Content-Length: 32
Content-Type: application/json
Date: Sun, 29 Mar 2015 17:06:58 GMT
Server: Werkzeug/0.10.1 Python/3.4.3
{
"error": "404: Not Found"
}
如果您还想覆盖来自 Flask 的默认 HTML 异常(以便它们也 return JSON),请在 app.run
之前添加以下内容:
from werkzeug.exceptions import default_exceptions
for ex in default_exceptions:
app.register_error_handler(ex, handle_error)
对于较旧的 Flask 版本(<=0.10.1,即目前任何 non-git/master 版本),将以下代码添加到您的应用程序以显式注册 HTTP 错误:
from werkzeug import HTTP_STATUS_CODES
for code in HTTP_STATUS_CODES:
app.register_error_handler(code, handle_error)
远非优雅,但下面的工作将 HTTPException
的所有子类绑定到一个错误处理程序:
from flask import jsonify
from werkzeug.exceptions import HTTPException
def handle_error(error):
code = 500
if isinstance(error, HTTPException):
code = error.code
return jsonify(error='error', code=code)
for cls in HTTPException.__subclasses__():
app.register_error_handler(cls, handle_error)
这是 Flask 0.12 兼容的,是一个很好的问题解决方案(它允许以 JSON 或任何其他格式呈现错误)
from functools import wraps
from flask import Flask, redirect, jsonify
app = Flask(__name__)
def get_http_exception_handler(app):
"""Overrides the default http exception handler to return JSON."""
handle_http_exception = app.handle_http_exception
@wraps(handle_http_exception)
def ret_val(exception):
exc = handle_http_exception(exception)
return jsonify({'code':exc.code, 'message':exc.description}), exc.code
return ret_val
# Override the HTTP exception handler.
app.handle_http_exception = get_http_exception_handler(app)
https://github.com/pallets/flask/issues/671#issuecomment-12746738
如果异常不起作用,您可以尝试 app.register_error_handler
(或以 non-decorator 的方式使用 app.errorhandler
)
在 Flask >=0.12 中实现这个的更简洁的方法是为每个 Werkzeug 异常显式注册处理程序:
from flask import jsonify
from werkzeug.exceptions import HTTPException, default_exceptions
app = Flask('test')
def handle_error(error):
code = 500
if isinstance(error, HTTPException):
code = error.code
return jsonify(error='error', code=code)
for exc in default_exceptions:
app.register_error_handler(exc, handle_error)
基于 Plain (non-HTML) error pages in REST api
我想 return json 完全不更改我的任何代码,所以我只是在我的代码顶部添加了以下内容
@app.errorhandler(500)
def error_500(exception):
return jsonify({"error": str(exception)}), 500, {'Content-Type': 'application/json'}
@app.errorhandler(400)
def error_400(exception):
return jsonify({"error": str(exception)}), 400, {'Content-Type': 'application/json'}
可以为非常通用的基础 class 注册错误处理程序,例如 HTTPException
甚至 Exception
。但是,请注意,这些捕获的数量会超出您的预期。
例如,HTTPException
的错误处理程序可能有助于将默认 HTML 错误页面转换为 JSON。但是,此处理程序将触发您不直接导致的事情,例如路由期间的 404 和 405 错误。请务必仔细制作您的处理程序,以免丢失有关 HTTP 错误的信息。
from flask import Flask, abort, jsonify, json
from werkzeug.exceptions import HTTPException
app = Flask('test')
app.config['JSON_SORT_KEYS'] = False
@app.errorhandler(HTTPException)
def handle_exception(e):
"""Return JSON instead of HTML for HTTP errors."""
# start with the correct headers and status code from the error
response = e.get_response()
# replace the body with JSON
response.data = json.dumps({
"error": {
"code": e.code,
"name": e.name,
"description": e.description,
}
})
print(response.data)
response.content_type = "application/json"
return response
@app.route('/')
def index():
abort(409)
@app.route('/aloha')
def aloha():
abort(400, "I'm not in the mood to talk!")
app.run(port=1234)
输出:
Exception
的错误处理程序对于更改向用户显示所有错误(甚至是未处理的错误)的方式似乎很有用。但是,这类似于执行 except Exception
:在 Python 中,它将捕获 所有 否则未处理的错误,包括所有 HTTP 状态代码。
在大多数情况下,为更具体的异常注册处理程序会更安全。由于 HTTPException
个实例是有效的 WSGI 响应,您也可以直接传递它们。
from werkzeug.exceptions import HTTPException
@app.errorhandler(Exception)
def handle_exception(e):
# pass through HTTP errors
if isinstance(e, HTTPException):
return e
# now you're handling non-HTTP exceptions only
return render_template("500_generic.html", e=e), 500
错误处理程序仍然遵循异常 class 层次结构。如果您同时为 HTTPException
和 Exception
注册处理程序,Exception
处理程序将不会处理 HTTPException
subclasses,因为 HTTPException
处理程序是更具体。