flask异常处理:abort、errorhandler、app_errorhandler,封装全局异常处理

1. abort()

abort()函数也叫视图终止函数,用于提前退出一个请求,并用指定的错误码返回。既然是视图终止函数,就是说abort()函数是写在视图中的。那么这个函数就不能处理由于url不合法引起的异常,因为一旦url不合法,是无法进入到视图函数中的。

flask-restful中的 abort() 的代码是封装的 flask 的 abort() 代码。

flask abort() 源码:

def abort(status, *args, **kwargs):
    return _aborter(status, *args, **kwargs)

flask-restful 的 abort() 源码:

def abort(http_status_code, **kwargs):
    try:
        original_flask_abort(http_status_code)
    except HTTPException as e:
        if len(kwargs):
            e.data = kwargs
        raise

这里的 original_flask_abort() 即 flask 的 abort()。其实我们也可以自己来封装abort()这个函数,来实现我们需要的功能。

1.1 使用方式一:传递一个错误码

from flask import abort

@app.route("/")
def index():
    # abort函数可以提前终止视图函数
    abort(404)

    # 下面这条消息无法打印出来,因为上面abort函数已经终止了这个视图函数的运行。
    print("我还在运行ing")
    return "Index Page"

参数http_status_code:传递状态码(错误码),必须是标准的http状态码。

直接返回给前端页面一个对应错误码的错误信息。

查看错误码:

from werkzeug.exceptions import default_exceptions
import pprint

pprint.pprint(default_exceptions)

结果:

如果是以下列表之外的,会报服务器内部错误:{"message": "Internal Server Error"}
可以看到2xx与3xx并不在此之列。


{400: <class 'werkzeug.exceptions.BadRequest'>,
 401: <class 'werkzeug.exceptions.Unauthorized'>,
 403: <class 'werkzeug.exceptions.Forbidden'>,
 404: <class 'werkzeug.exceptions.NotFound'>,
 405: <class 'werkzeug.exceptions.MethodNotAllowed'>,
 406: <class 'werkzeug.exceptions.NotAcceptable'>,
 408: <class 'werkzeug.exceptions.RequestTimeout'>,
 409: <class 'werkzeug.exceptions.Conflict'>,
 410: <class 'werkzeug.exceptions.Gone'>,
 411: <class 'werkzeug.exceptions.LengthRequired'>,
 412: <class 'werkzeug.exceptions.PreconditionFailed'>,
 413: <class 'werkzeug.exceptions.RequestEntityTooLarge'>,
 414: <class 'werkzeug.exceptions.RequestURITooLarge'>,
 415: <class 'werkzeug.exceptions.UnsupportedMediaType'>,
 416: <class 'werkzeug.exceptions.RequestedRangeNotSatisfiable'>,
 417: <class 'werkzeug.exceptions.ExpectationFailed'>,
 418: <class 'werkzeug.exceptions.ImATeapot'>,
 422: <class 'werkzeug.exceptions.UnprocessableEntity'>,
 423: <class 'werkzeug.exceptions.Locked'>,
 428: <class 'werkzeug.exceptions.PreconditionRequired'>,
 429: <class 'werkzeug.exceptions.TooManyRequests'>,
 431: <class 'werkzeug.exceptions.RequestHeaderFieldsTooLarge'>,
 451: <class 'werkzeug.exceptions.UnavailableForLegalReasons'>,
 500: <class 'werkzeug.exceptions.InternalServerError'>,
 501: <class 'werkzeug.exceptions.NotImplemented'>,
 502: <class 'werkzeug.exceptions.BadGateway'>,
 503: <class 'werkzeug.exceptions.ServiceUnavailable'>,
 504: <class 'werkzeug.exceptions.GatewayTimeout'>,
 505: <class 'werkzeug.exceptions.HTTPVersionNotSupported'>}

1.2 使用方式二:传递一个json格式字符串

from flask import abort, jsonify

@app.route("/")
def index():
    code = 50000
    data = [{"data1": "lalallala", {"data2": "lolololo"}]
    json_data = jsonify({"code": code, "data": data})
    abort(json_data)

    # 下面这条消息无法打印出来,因为上面abort函数已经终止了这个视图函数的运行。
    print("我还在运行ing")
    return "Index Page"

这种方法相当于 return ,直接把传入abort中的数据返回到前端。

1.3 使用方式三:传递一个响应体

from flask import abort, Response

@app.route("/")
def index():
    res = Response("Not Found", 404, {"name": "ttytty"})  # Response也可以返回响应体信息
    abort(res)

    # 下面这条消息无法打印出来,因为上面abort函数已经终止了这个视图函数的运行。
    print("我还在运行ing")
    return "Index Page"

直接返回给前端这个响应体。方式二和方式三很相似。

2. errorhandler

捕捉当前app或蓝图的状态码,然后可以进行自定义处理。

2.1 简单使用:

from flask import jsonify
from . import admin

@admin.errorhandler(404)
def error_404(error):
    """这个handler可以catch住所有abort(404)以及找不到对应router的处理请求"""
    response = dict(status=0, message="404 Not Found")
    return jsonify(response), 404

@admin.errorhandler(Exception)
def error_500(error):
    """这个handler可以catch住所有的abort(500)和raise exeception."""
    response = dict(status=0, message="500 Error")
    return jsonify(response), 400

class MyError(Exception):
    """自定义错误类"""
    pass

@admin.errorhandler(MyError)
def MyErrorHandle(error):
    response = dict(status=0, message="400 Error")
    return jsonify(response), 400

2.2 封装成全局异常捕获处理:

  1. 自定义异常类(有需要的话)

from werkzeug.exceptions import HTTPException


class EigenException(HTTPException):
    code = 500
    eigen_code = 4000
    description = 'Inner Server Error'


class RequestError(EigenException):
    code = 400


class DataNotFound(RequestError):
    code = 404
    eigen_code = 4004
    description = 'Data Not Found'

    def __init__(self, message):
        self.description = '%s Not Found' % message


class InvalidRequest(RequestError):
    eigen_code = 4005
    description = 'Invalid Request URL'


class MissingKey(RequestError):
    eigen_code = 4006
    description = 'Missing Key'

    def __init__(self, key):
        self.description = 'Missing Key `%s`' % key
  1. 捕获异常并处理:

# 制定一个响应
def json_response(code, error, status_code):
    response = make_response(json.dumps(dict(code=code, error=error)), status_code)
    response.headers['Content-Type'] = 'application/json; charset=utf-8'
    return response

# 异常捕获处理
@app.errorhandler(Exception)
def handler_exception(e):
    if isinstance(e, 其他异常):
        code, status_code, error = 4000, 400, e.description
    elif isinstance(e, EigenException):
        code, status_code, error = e.eigen_code, e.code, e.description
    elif isinstance(e, HTTPException):
        code, status_code, error = e.code, e.code, e.description
    else:
        code, status_code, error = 5000, 500, '%s(%s)' % (e.__class__.__name__, str(e))
    return json_response(code, error, status_code)

3. app_errorhandler

捕捉全局状态码,并进行自定制异常处理

在蓝本中编写错误处理程序有点不同,如果使用errorhandler修饰器,那么只有蓝本中的错误才会触发。如果想注册全局的错误处理程序,要用app_errorhandler。

例如:


from bookapp import bokkapp


@bookapp.app_errorhandler(Exception)
def handler_exception(e):
    if isinstance(e, 其他异常):
        code, status_code, error = 4000, 400, e.description
    elif isinstance(e, EigenException):
        code, status_code, error = e.eigen_code, e.code, e.description
    elif isinstance(e, HTTPException):
        code, status_code, error = e.code, e.code, e.description
    else:
        code, status_code, error = 5000, 500, '%s(%s)' % (e.__class__.__name__, str(e))
    response = dict(code=code, status=status_code, msg=error)
    return jsonify(response)

**注意: **当我们不是使用的工厂模式创建app时,app.errorhandler(401),即可捕捉全局401状态;若使用了create_app方式创建app,则无法进行捕捉,若想捕捉,可以在蓝图中写,如admin.errorhandler(401),即捕捉admin蓝图下所有401状态码,admin.app_errorhandler(401),则是捕捉的全局的401状态码,即其他蓝图中的401状态,也会被捕捉,进行处理

参考文章:

  1. https://www.cnblogs.com/huchong/p/9205651.html
  2. https://www.cnblogs.com/fiona-zhong/p/10218338.html
posted @ 2019-08-08 20:16  长安223  阅读(3895)  评论(0编辑  收藏  举报