1.自定义异常对象
flask所有的异常都继承自 HTTPException,例如werkzeug.exceptions下
class BadRequest(HTTPException):
"""*400* `Bad Request`
Raise if the browser sends something to the application the application
or server cannot handle.
"""
code = 400
description = (
'The browser (or proxy) sent a request that this server could '
'not understand.'
)
class ClientDisconnected(BadRequest):
"""Internal exception that is raised if Werkzeug detects a disconnected
client. Since the client is already gone at that point attempting to
send the error message to the client might not work and might ultimately
result in another exception in the server. Mainly this is here so that
it is silenced by default as far as Werkzeug is concerned.
Since disconnections cannot be reliably detected and are unspecified
by WSGI to a large extent this might or might not be raised if a client
is gone.
.. versionadded:: 0.8
"""
class SecurityError(BadRequest):
"""Raised if something triggers a security error. This is otherwise
exactly like a bad request error.
.. versionadded:: 0.9
"""
class BadHost(BadRequest):
"""Raised if the submitted host is badly formatted.
.. versionadded:: 0.11.2
"""
class Unauthorized(HTTPException):
"""*401* `Unauthorized`
Raise if the user is not authorized. Also used if you want to use HTTP
basic auth.
"""
code = 401
description = (
'The server could not verify that you are authorized to access '
'the URL requested. You either supplied the wrong credentials (e.g. '
'a bad password), or your browser doesn\'t understand how to supply '
'the credentials required.'
)
class Forbidden(HTTPException):
"""*403* `Forbidden`
Raise if the user doesn't have the permission for the requested resource
but was authenticated.
"""
code = 403
description = (
'You don\'t have the permission to access the requested resource. '
'It is either read-protected or not readable by the server.'
)
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.'
)
...
...
...
自定制异常对象
控制器app/v1/client.py
@api.route('/register', methods=['POST'])
def create_client():
data = request.json
form = ClientForm(data=data) # 接收json格式数据指定data=data
if form.validate():
promise = {
ClientTypeEnum.USER_EMAIL: __register_user_by_email,
ClientTypeEnum.USER_MOBILE: __register_user_by_mobile,
ClientTypeEnum.USER_MINA: __register_user_by_mobile,
}
promise[form.type.data]() # form.type.data 在验证器中已经换成了枚举类型
else:
from app.libs.error_code import My_notfound
raise My_notfound()
return "success" # 暂时
虽然上面能返回异常,但是返回的是html格式,不是json格式,我们要深度定制HTTPException
2.自定义APIException
app/libs/my_exception.py
# -*- coding: utf-8 -*-
# @Author: Lai
from werkzeug.exceptions import HTTPException
from flask import request, json
class APIException(HTTPException):
code = 500
msg = "this is valid" # 相当于description
error_code = 999
# 此处相当巧妙,若找不到实例属性,会直接找类属性
def __init__(self, code=None, msg=None, error_code=None, response=None):
super(APIException, self).__init__(msg,response)
if code:
self.code = code
if msg:
self.msg = msg
if error_code:
self.error_code = error_code
def get_body(self, environ=None):
request_data = request.method + " " + request.full_path.split('?')[0]
data_dict = {
"code": self.code,
"msg": self.msg,
"error_code": self.error_code,
"request": request_data
}
return json.dumps(data_dict)
def get_headers(self, environ=None):
return [('Content-Type', 'application/json')]
改写上面的app/libs/error_code.py
# -*- coding: utf-8 -*-
# @Author: Lai
from app.libs.my_exception import APIException
class My_notfound(APIException):
code = 404
msg = "not found"
error_code = 1006
控制器app/v1/client.py
@api.route('/register', methods=['POST'])
def create_client():
data = request.json
form = ClientForm(data=data) # 接收json格式数据指定data=data
if form.validate():
promise = {
ClientTypeEnum.USER_EMAIL: __register_user_by_email,
ClientTypeEnum.USER_MOBILE: __register_user_by_mobile,
ClientTypeEnum.USER_MINA: __register_user_by_mobile,
}
promise[form.type.data]() # form.type.data 在验证器中已经换成了枚举类型
else:
from app.libs.error_code import My_notfound
raise My_notfound()
return "success" # 暂时
此时抛出的就是json格式异常了,但是问题又来了,验证器的返回错误多种多样,如何通过抛出一个异常匹配多种错误。
解决办法:
结果
3.重写WTForms
我们想要在验证器中抛异常,但是WTForms是不会抛异常的,我们开始自定制WTForms的Form类
在app/validators/forms.py下,必须导入我们自定制的Form,然后在控制器app/v1/client.py下
# -*- coding: utf-8 -*-
# @Author: Lai
from app.libs.red_print import Red_Print
from app.models.user import User
from app.validators.forms import ClientForm, EmailClientForm
from app.libs.enums import ClientTypeEnum
from flask import request
api = Red_Print('client')
@api.route('/register', methods=['POST'])
def create_client():
data = request.json
form = ClientForm(data=data).validate_for_api()
promise = {
ClientTypeEnum.USER_EMAIL: __register_user_by_email,
ClientTypeEnum.USER_MOBILE: __register_user_by_mobile,
ClientTypeEnum.USER_MINA: __register_user_by_mobile,
}
promise[form.type.data]() # form.type.data 在验证器中已经换成了枚举类型
return "ok" # 暂时
def __register_user_by_email():
data = request.json
form = EmailClientForm(data=data).validate_for_api()
User.register_by_email(form.nickname.data,
form.account.data,
form.password.data)
def __register_user_by_mobile():
pass
def __register_user_by_mina():
pass
就实现了再验证器中抛出异常。
4.已知异常与未知异常
manage.py中(只有flask1.0以上才能捕获Exception)
# -*- coding: utf-8 -*-
# @Author: Lai
# -*- coding: utf-8 -*-
# @Author: Lai
from app import create_app
from app.models import db
from flask_script import Manager
from flask_migrate import Migrate, MigrateCommand
from app.libs.my_exception import APIException
from werkzeug.exceptions import HTTPException
from app.libs.error_code import ServerError # 自定义
app = create_app()
# manager = Manager(app)
# migrate = Migrate(app, db)
# manager.add_command('db', MigrateCommand)
@app.errorhandler(Exception)
def frame_error(e):
if isinstance(e, APIException):
return e
elif isinstance(e, HTTPException): # 若异常时HTTPException类型按APIException抛出
msg = e.description
code = e.code
error_code = 1007
return APIException(msg=msg, code=code, error_code=error_code)
else:
#log
if not app.config['DEBUG']:
return ServerError() # 未知异常的抛出
else:
raise e
if __name__ == "__main__":
app.run(debug=app.config['DEBUG'])