Flask通用异常处理程序无法捕获405错误



我根据以下文档创建了一个异常处理程序:

import json
from flask import Blueprint, abort, current_app, jsonify, make_response, request
from werkzeug.exceptions import HTTPException
import pmo.service as pmo
ops = Blueprint("ops", __name__)

@ops.route("/today", methods=["GET"])
def get_today():
current_app.logger.info("Getting an entry for 'today'")
try:
return jsonify(pmo.get_today_entry())
except IndexError:
abort(404, "No entry for today")

@ops.errorhandler(Exception)
def handle_exception(e):
# pass through HTTP errors as json
if isinstance(e, HTTPException):
response = e.get_response()
payload = json.dumps({
"code": e.code,
"name": e.name,
"description": e.description,
})
response.data = f"{payload}n"
response.content_type = "application/json"
return make_response(response, e.code)
# now handle non-HTTP exceptions only
response_body = {"code": 500, "message": "unhandled exception occurred", "details": str(e)}
return make_response(response_body, 500)

我之所以决定使用这种方法,是因为我正在开发RESTapi,并且希望去掉任何html响应。尽管如此,当我发出POST请求以触发405错误时,它被返回为html文档,而不是json:

❯ curl -X POST localhost:5000/today
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>

当GET请求按预期处理时:

❯ curl localhost:5000/today
{"code": 404, "name": "Not Found", "description": "No entry for a given day"}

事实上,405上没有调用错误处理程序,我已经用调试器验证了这一点。

我做错了什么?

您的错误处理程序需要在应用程序对象上,而不是蓝图上。尝试:

@app.errorhandler(Exception)
def handle_exception(e):
...

除此之外,我认为您的代码没有任何问题。

正如@KenKinder在评论中善意地指出的那样,问题在于通用异常处理程序的位置。在将它移动到应用程序的入口点后,它开始像一个符咒一样工作。

已经回答了,它需要继续@app,但需要一些进一步的细节:

在具有蓝图的模块化应用程序中,大多数错误处理程序将按预期工作。但是,对于404和405异常的处理程序有一个警告。

这是因为蓝图不"拥有"特定的URL空间,因此如果给定无效的URL,应用程序实例无法知道应该运行哪个蓝图错误处理程序。

相关文档:https://flask.palletsprojects.com/en/2.2.x/errorhandling/#blueprint-错误处理程序

最新更新