PS 最近才入坑flask,之前一直以pyqt5为主,在使用flask的过程中碰到了居多的难题和坑,记录一下,笔记有点杂乱,能保证看懂就行。
自定义异常反馈格式
基本上网上的一些教程都有,以下代码不做过多说明
# error_types.py
import json
from flask import request
from werkzeug.exceptions import HTTPException
class APIException(HTTPException):
"""API错误基类"""
code = 500
msg = 'Sorry, we made a mistake Σ(っ °Д °;)っ'
error_code = 999
def __init__(self, msg=None, code=None, error_code=None, headers=None):
if code:
self.code = code
if msg:
self.msg = msg
if error_code:
self.error_code = error_code
super(APIException, self).__init__(msg, None)
@staticmethod
def get_error_url():
"""获取出错路由和请求方式"""
method = request.method
full_path = str(request.full_path)
main_path = full_path.split('?')[0]
res = method + ' ' + main_path
return res
def get_body(self, environ=None, scope=None):
"""异常返回信息"""
body = dict(
msg=self.msg,
error_code=self.error_code,
request=self.get_error_url()
)
text = json.dumps(body)
return text
def get_headers(self, environ=None, scope=None):
"""异常返回格式"""
return [("Content-Type", "application/json")]
class Success(APIException):
"""操作成功"""
code = 201
msg = 'Ok'
error_code = 0
class ServerError(APIException):
"""服务器错误/未知错误"""
code = 500
msg = 'Sorry, we made a mistake Σ(っ °Д °;)っ'
error_code = 9999
全局异常捕获
网上也能搜到很多,需要注意:errorhandler和app_errorhandler的使用
# errors.py
from flask import Blueprint
from werkzeug.exceptions import HTTPException
from applications.libs.error_type import APIException, ServerError
exception_bp = Blueprint("error", __name__)
"""
如果用的工厂模式创建app,需要使用app_errorhandler捕获全局异常
如果是常规的 app = Flask(__name__), 使用errorhandler即可捕获全局异常
PS 网上说的,没有一一测试过
"""
@exception_bp.app_errorhandler(Exception)
def framework_error(e):
if isinstance(e, APIException):
# 自定义好的异常
return e
elif isinstance(e, HTTPException):
code = e.code
msg = e.description
error_code = 1001 # 已知异常状态码, 包含常规的404、405等等已经被flask定义好的异常,一可以根据需求进行细分
return APIException(msg=msg, code=code, error_code=error_code)
else:
return ServerError()
坑来了:使用flask-restful
"""
当没有使用flask-restful时
是通过直接使用app.route()来反馈视图函数的内容时,发现所有的异常都会通过 framework_error,反馈格式也是固定的
但是 当我使用flask-restful后,路由分发用的 库里的Api
"""
from flask_restful import Api
api = Api(bp)
class ErrorApi(Resource):
def get(self):
return abort(404) # 注意此处的404
api.add_resource(ErrorApi, '/error')
当使用以上代码路由分发时,
访问 http://127.0.0.1:5000/error # 路由存在,自主abort(404)
反馈如下, 状态码 404
{
"message": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again."
}
访问 http://127.0.0.1:5000/error/s # 路由不存在,直接404
反馈如下, 状态码 404
{
"msg": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.",
"error_code": 1001,
"request": "GET /error/s"
}
后续我自主abort(405)
访问 http://127.0.0.1:5000/error # 路由存在,自主abort(405)
反馈如下, 状态码 405
{
"message": "The method is not allowed for the requested URL."
}
解决思路
关于这部分我找了很久的资料,最后找到一个说法,如下图,具体的链接在底部
原因找到了,要怎么解决呢?
之后由看到一边文章,【Flask-Restful在非调试模式下接管Flask的异常处理】
这里提出了重写API的error_router的思路
当然,我试过博主的方法,依旧没解决,但是这个想法让我看一部分Api的源码,然后找到了里面的handle_error这个函数,处理异常的函数。
我个人想到的思路就是重写该方法,让其不去处理异常,而是爆出异常,这样我们的全局异常捕获函数就能找到该异常
# base_api.py
rom flask_restful import Api as _Api
from werkzeug.exceptions import HTTPException
class Api(_Api):
def handle_error(self, e):
if isinstance(e, HTTPException):
raise HTTPException()
else:
raise Exception()
api = Api()# 调用自定义的Api去路由分发
当使用以上代码路由分发时,
访问 http://127.0.0.1:5000/error # 路由存在,自主abort(404)
反馈如下, 状态码 404
{
"msg": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.",
"error_code": 1001,
"request": "GET /error"
}
访问 http://127.0.0.1:5000/error/s # 路由不存在,直接404
反馈如下, 状态码 404
{
"msg": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.",
"error_code": 1001,
"request": "GET /error/s"
}
后续我自主abort(405)
访问 http://127.0.0.1:5000/error # 路由存在,自主abort(405)
反馈如下, 状态码 405
{
"msg": "The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.",
"error_code": 1001,
"request": "GET /error/s"
}
至此,问题解决!
PS 重写的 Api 不确定会不会有其他问题,这个需要过多实践才行
相关资料
版权声明:本文为weixin_43868038原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。