Flask-11-应用错误处理

一、错误处理器

在 Flask 中发生错误时,会返回一个相应的 HTTP 状态码 。状态码 400-499 表示客户端的请求数据或者与之相关的错误。状态码 500-599 表示服务器或者应用本身的错误。
当错误发生时,你可能想要向用户显示自定义的出错页面。注册出错处理器可以 做到这点。
一个出错处理器是一个函数,当发生某类错误时返回一个响应。类似于一个视图 函数,当请求 URL 匹配时返回一个响应。它传递了正在处理的错误的实例,基本 上是一个 HTTPException 。
响应的状态代码不会设置为处理器的代码。请确保从处理器返回一个响应时提供 适当的 HTTP 状态码。

1.1 原始的错误堆栈

@app.route('/')
def hello_world(): 
    # 模拟错误
    num = 1 / 0
    return 'Hello World!'

页面上的错误

Flask-11-应用错误处理
image.png


后台的错误

Flask-11-应用错误处理
image.png


但是这样的错误,尤其是前端的错误,给人的感觉是不太友好。


二、注册

通过使用 errorhandler() 装饰函数来注册或者稍后使用 register_error_handler() 来注册。记得当返回响应的时候设置出错代码。

@app.route('/')
@app.errorhandler(werkzeug.exceptions.BadRequest)
def hello_world():  # put application's code here
    # 这里直接返回了一个字符串,给浏览器
    try:
        num = 1 / 0
    except Exception as e:
        return '发生了异常!'500
Flask-11-应用错误处理
image.png


Flask-11-应用错误处理
image.png

当注册时, werkzeug.exceptions.HTTPException 的子类,如 BadRequest ,和它们的 HTTP 代码是可替换的。( BadRequest.code == 400 )
因为 Werkzeug 无法识别非标准 HTTP 代码,所以它们不能被注册。
相反,使用 适当的代码定义一个 HTTPException 子类, 注册并抛出异常类。

class MyException(werkzeug.exceptions.HTTPException):
    code = 5000
    description = '除数不能为0'


# 路由
@app.route('/')
def hello_world():  # put application's code here
    # 这里直接返回了一个字符串,给浏览器
    try:
        num = 1 / 0
    except Exception as e:
        raise MyException

三、处理

在构建 Flask 应用时,您 遇到异常。如果在处理请求时(且您没有注册 错误处理器),你的代码中断了,那么将默认返回“ 500 内部服务器错误” ( InternalServerError )。同样,如果请求被发送到未注册的路由,则会产生 “ 404 未找到” ( NotFound )错误。如果路由接收到被禁止的请求方法,则会产生“ 405 方法被禁止” (MethodNotAllowed) 。Flask 默认提供这些 HTTPException 的子类。
Flask 使您能够注册 Werkzeug 提供的任意 HTTP 异常。但是,默认的 HTTP 异 常返回简单的异常页。您可能希望在发生错误时向用户显示自定义错误页面。可 以通过注册错误处理器来完成。
在处理请求时,当 Flask 捕捉到一个异常时,它首先根据代码检索。如果该代码 没有注册处理器,它会根据类的继承来查找,确定最合适的注册处理器。如果找 不到已注册的处理器,那么 HTTPException 子 类会显示一个关于代码的通用消息。没有代码的异常会被转化为一个通用的 “ 500 内部服务器错误”。
例如,如果一个 ConnectionRefusedError的实例被抛出,并且一个出错 处理器注册到 ConnectionErrorConnectionRefusedError , 那么会使用更合适的 ConnectionRefusedError 来处理异常实例,生成响应。
当一个蓝图在处理抛出异常的请求时,在蓝图中注册的出错处理器优先于在应用 中全局注册的出错处理器。但是,蓝图无法处理 404 路由错误,因为 404 发生 的路由级别还不能检测到蓝图。

四、通用异常处理器

可以为非常通用的基类注册异常处理器,例如 HTTPException 基类或者甚至 Exception 基类。但是,请注意,这样会捕捉到超出你预期的异常。
例如,基于 HTTPException 的异常处理器对于把缺省的 HTML 出错页面转换 为 JSON 非常有用,但是这个处理器会触发不由你直接产生的东西,如路由过程 中产生的 404 和 405 错误。请仔细制作你的处理器,确保不会丢失关于 HTTP 错误的信息。

# 定义一个全局异常处理函数
@app.errorhandler(HTTPException)
def handle_exception(e):
    response = e.get_response()
    response.data = json.dumps({
        "code": e.code,
        "name": e.name,
        "description": e.description,
    })
    response.content_type = "application/json"
    return response


@app.route("/exe")
def exec():
    try:
        num = 1 / 0
    except Exception as e:
        # 有问题就abort
        abort(500)

这样页面上就会有统一的json错误处理。

Flask-11-应用错误处理
image.png


这里只是实现一种方式,在真正的生产中,错误信息一定会定义的更加细致。
当然,在模板技术中,还可以直接返回500错误到模板中


@app.route("/exe")
def exec():
    try:
        num = 1 / 0
    except Exception as e:
        return render_template("500.html", e=e), 500

五、自定义错误页面

有时在构建 Flask 应用时,您可能希望产生一个 HTTPException ,向用户发出信号,提示请求有 问题。幸运的是,Flask 附带了一个方便的来自 werkzeug 的 abort() 函数,可以中止请求,产生 HTTP 错误。它还提供一个带 有基本描述的朴素的黑白页面。
依据错误代码,用户可以或多或少,知道一些错误。
考虑下面的代码,我们可能有一个用户配置文件路由,如果用户未能传递用户名, 我们可以引发“ 400 错误请求”。如果用户传递了用户名,但是我们找不到它, 我们引发“ 404 页面未找到”。

@app.errorhandler(404)
def page_not_found(e):
    # 等出现404时,就去404页面
    return render_template('404.html'), 404


@app.route("/notfound")
def notfound():
    abort(404)

当使用 应用工厂 时:

def page_not_found(e):
  return render_template('404.html'), 404

def create_app(config_filename):
    app = Flask(__name__)
    app.register_error_handler(404, page_not_found)
    return app

当使用 使用蓝图进行应用模块化 时:

from flask import Blueprint

blog = Blueprint('blog', __name__)

# as a decorator
@blog.errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

# or with register_error_handler
blog.register_error_handler(500, internal_server_error)

在 使用蓝图进行应用模块化 中,大多数错误处理器会按预期工作,但是处理 404 和 405 错误的处理器比较特殊,要小心。这些错误处理器只有从适当的 raise 语句调用时或者在另一个蓝印在视图函数中调用 abort 时才会调用。相反, 例如非法 URL 访问时,则不会调用。
这是因为蓝印不“拥有”一定的 URL 空间,所以应用实例无法知道非法 URL 访 问应当调用哪个蓝印的错误处理器。如果需要基于 URL 前缀配置不同的处理策略, 那么可以使用 rquest 代理对象在应用层面进行配置。


原文始发于微信公众号(Python之家):Flask-11-应用错误处理

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/198254.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!