白草黄云网

Flask 学习-69.捕获异常钩子函数errorhandler

Flask 学习-69.捕获异常钩子函数errorhandler

前言

flask 运行请求出现异常时,学习捕会先触发对应的获异函数异常钩子,比如出现404时,常钩会根据NotFound 异常类返回404状态码。学习捕
我们也可以根据捕获异常钩子errorhandler 来自定义异常的获异函数输出。

404 NotFound

以404 NotFound 为例,常钩在werkzeug.exceptions中可以找到

class NotFound(HTTPException):    """*404* `Not Found`    Raise if a resource does not exist and never existed.    """    code = 404    description = (        "The学习捕 requested URL was not found on the server. If you entered"        " the URL manually please check your spelling and try again."    )

NotFound 类继承了一个基类HTTPException

class HTTPException(Exception):    """The base class for all HTTP exceptions. This exception can be called as a WSGI    application to render a default error page or you can catch the subclasses    of it independently and render nicer error messages.    """    code: t.Optional[int] = None    description: t.Optional[str] = None

我们只需要继承HTTPException类,自定义code和description就可以指定不同状态码返回了。获异函数

当我们访问一个不存在的常钩地址,先抛出NotFound异常,学习捕然后触发异常钩子,获异函数返回对应的常钩code和description

于是我们可以自定义这个404 页面

404

404 page object not found !

errorhandler 使用

errorhandler 相关源码

@setupmethod    def errorhandler(        self, code_or_exception: t.Union[t.Type[Exception], int]    ) ->t.Callable[[ErrorHandlerCallable], ErrorHandlerCallable]:        """Register a function to handle errors by code or exception class.        A decorator that is used to register a function given an        error code.  Example::            @app.errorhandler(404)            def page_not_found(error):                return 'This page does not exist', 404        You can also register handlers for arbitrary exceptions::            @app.errorhandler(DatabaseError)            def special_exception_handler(error):                return 'Database connection failed', 500

通过使用 errorhandler() 装饰函数来注册或者使用 register_error_handler() 来注册

@app.errorhandler(werkzeug.exceptions.BadRequest)def handle_bad_request(e):    return 'bad request!', 400# or, without the decoratorapp.register_error_handler(400, handle_bad_request)

使用@app.errorhandler()装饰器返回自定义的页面

from flask import Flask, request, g, abort, Response, render_templateapp = Flask(__name__)@app.errorhandler(404)def error_404(error):    return render_template('404.html'), 404@app.route("/demo", methods=["GET"])def demo():    return { 'msg': 'ok'}if __name__ == '__main__':    app.run()

使用的时候需注意三点
1.errorhandler()括号里面传对应状态码或者一个异常类
2.函数error_404(error) 括号里面必须传一个位置参数接收异常
3.return 返回的时候需带上状态码(404),没带上状态码默认返回200

errorhandler 传异常类示例

werkzeug.exceptions导入异常类

from werkzeug.exceptions import NotFound@app.errorhandler(NotFound)def error_404(error):    return render_template('404.html'),学习捕 404

效果和上面传404 参数一样

自定义400 bad request

请求参数不合法时,我们一般会返回400 bad request,获异函数 默认返回的是一个html页面

在开发接口的时候,我们希望统一返回json 格式

@app.errorhandler(400)def error_400(error):    return { 'msg': '请求参数不合法',常钩 'data': f'{ error}'}, 400@app.route("/demo", methods=["GET"])def demo():    if request.args.get('username'):        abort(400)    return { 'msg': 'ok'}

当访问一个不存在的地址时,就会返回400的json格式

HTTP/1.0 400 BAD REQUESTContent-Type: application/jsonContent-Length: 145Server: Werkzeug/2.0.1 Python/3.8.5Date: Sun, 11 Sep 2022 14:19:53 GMT{   "data": "400 Bad Request: The browser (or proxy) sent a request that this server could not understand.",   "msg": "请求参数不合法"}

处理

在处理请求时,当 Flask 捕捉到一个异常时,它首先根据代码检索。如果该代码没 有注册处理器,它会根据类的继承来查找,确定最合适的注册处理器。如果找不到已 注册的处理器,那么 HTTPException 子类会显示 一个关于代码的通用消息。没有代码的异常会被转化为一个通用的 500 内部服务器 错误。

例如,如果一个 ConnectionRefusedError 的实例被抛出,并且一个出错处 理器注册到 ConnectionError 和 ConnectionRefusedError ,那么 会使用更合适的 ConnectionRefusedError 来处理异常实例,生成响应。

当一个蓝图在处理抛出异常的请求时,在蓝图中注册的出错处理器优先于在应用中全 局注册的出错处理器。
但是,蓝图无法处理 404 路由错误,因为 404 发生的路由级 别还不能检测到蓝图。

通用异常处理器

可以为非常通用的基类注册异常处理器,例如 HTTPException 基类或者甚至 Exception 基类。但是,请注意,这样会捕捉到超出你预期的异常。

基于 HTTPException 的异常处理器对于把缺省的 HTML 出错页面转换为 JSON 非常有用,但是这个处理器会触发不由你直接产生的东西,
如路由过程中产生的 404 和 405 错误。请仔细制作你的处理器,确保不会丢失关于 HTTP 错误的信息。

from flask import jsonfrom werkzeug.exceptions import HTTPException@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({         "code": e.code,        "name": e.name,        "description": e.description,    })    response.content_type = "application/json"    return response

基于 Exception 的异常处理器有助于改变所有异常处理的表现形式,甚至包含 未处理的异常。但是,与在 Python 使用 except Exception: 类似,这样会捕 获 所有 未处理的异常,包括所有 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

异常处理器仍然遵循异常烦类的继承层次。如果同时基于 HTTPException 和 Exception 注册了异常处理器, Exception 处理器不会处理 HTTPException 子类,因为 HTTPException 更有针对性。

未处理的异常 500

当一个异常发生时,如果没有对应的异常处理器,那么就会返回一个 500 内部服务错误。关于此行为的更多内容参见 flask.Flask.handle_exception() 。

如果针为 InternalServerError 注册了异常处理器,那么出现内部服务错误时就 会调用这个处理器。自 Flask 1.1.0 开始,总是会传递一个 InternalServerError 实例给这个异常处理器,而不是以前的未处理异常。原始 的异常可以通过 e.original_error 访问。在 Werkzeug 1.0.0 以前,这个属性 只有未处理异常有。建议使用 getattr 访问这个属性,以保证兼容性。

@app.errorhandler(InternalServerError)def handle_500(e):    original = getattr(e, "original_exception", None)    if original is None:        # direct 500 error, such as abort(500)        return render_template("500.html"), 500    # wrapped unhandled error    return render_template("500_unhandled.html", e=original), 500

未经允许不得转载:白草黄云网 » Flask 学习-69.捕获异常钩子函数errorhandler