一,URL路径
二, 响应状态码
所有API响应遵守HTTP规范,常见的HTTP状态码如下所示。
状态码 |
描述 |
1xx |
信息状态码 |
2xx |
成功状态码 |
3xx |
重定向状态码 |
4xx |
客户端错误码 |
5xx |
服务器错误码 |
请求被正确返回
其返回参数定义如下:
参数 |
类型 |
是否必需 |
描述 |
code |
int64 |
是 |
正确状态码 |
data |
obj |
是 |
响应的请求数据 |
请求调用失败,必须返回出错的相信信息,参数定义如下:
参数 |
类型 |
是否必须 |
描述 |
code |
int64 |
是 |
业务错误码 |
message |
string |
是 |
业务错误信息,与code一一对应,用于表明code的含义,应尽量简短,抽象,具有概括性和通用性。 |
cause |
string |
是 |
导致此错误的原因,也可用于给接口调用者提示解决此错误的办法,相同的code可对应不同的cause |
detail |
obj |
否 |
错误详细信息,供调用方查看和展示给最终用户的信息 |
备注:
- 前三位为 HTTP标准状态码,中间三位为系统内全局唯一的微服务错误码标识号,后三位为自定义状态码,应尽量抽象,具有概括性和通用性。
- 对于参数不合法、json格式不对等由客户端调用API代码不对导致的错误,code后3位为000,原因在cause中说明。
- 对于需要由客户端判断,用于处理UI和具体功能逻辑的错误,code后3位表明具体错误,细节在detail中说明。
三,错误码方案
PDI产品后期需要嵌入到爱数其他的产品中去,所以可以采取动态配置的方案,实现针对不同的产品,使用不同的错误码。
常见的错误码:
- 400XXX000: 参数不合法、json格式不对等由客户端调用API代码不对导致的错误
- 500XXX000:服务内部错误
- 501XXX000:方法为实现
四,Flask 异常方案
Flask内部通过继承HTTPException类来处理异常,同样,我们可以自定义自己的异常基类类(继承自HTTPException),定义好返回的错误码,请求的url,错误原因等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| class APIException(HTTPException): code = 500 message = 'sorry, we made a mistake' error_code = 999 cause = 'just a mistake' detail = None dump_json = False
def __init__(self, msg=None, code=None, error_code=None, cause=None, header=None, detail=None): if code: self.code = code if error_code: self.error_code = error_code if msg: self.msg = msg if cause: self.cause = cause if detail: self.detail = detail super(APIException, self).__init__(msg, None)
def get_body(self, environ=None): body = dict( message=self.message, code=self.error_code, cause=self.cause ) if self.detail: body.update({"detail": self.detail})
data = json.dumps(body) if self.dump_json else body
return data
def get_headers(self, environ=None): """Get a list of headers.""" return [('Content-Type', 'application/json')]
|
定义好基类之后,派生出各种各样的异常类,自由定义各种状态码的错误及对应的错误信息,出现该异常后,抛出异常。比如:
1 2 3 4
| class NotFound(APIException): code = 404 message = 'the resource are not found' error_code = 1001
|
目前定义的派生类有:
- Success
- DeleteSucess
- UpdateSucess
- ServerError
- ParameterException
- NotFound
- AuthFailed
- Forbidden
在程序中使用。
1 2 3 4 5 6 7
| @input_bp.route('/input', methods=['POST']) def input_m(): d = request.get_json()
if "file_id" not in d or "op_type" not in d: return ParameterException(message='file_id 和 op_type两个参数不能为空').get_body() pass
|
虽然我们可以在可能出错的地方,继承自己的异常类,然后抛出,但是并不是所有的异常我们都能提前预知。比如参数错误等异常,我们可以提前预知并处理好,但是如果出现逻辑问题等提前没法感知的异常,就不是我们能够控制并处理的。所以我们还需要全局捕获所有异常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @app.errorhandler(Exception) def framework_error(e): api_logger.error("error info: %s" % e) if isinstance(e, APIException): return e if isinstance(e, HTTPException): code = e.code msg = e.description error_code = 1007 return APIException(msg, code, error_code) else: if not app.config['DEBUG']: return ServerError().get_body() else: return e
|
如此,Flask中出现的所有异常皆可处理了,保证程序的健壮性。co
五, Sanic异常方案
可以理解sanic为flask的升级版,采用协程机制,并发与效率都比flask高,用法基本上与flask一致。
与flask不同的是:
- 基类继承自HTTPResponse,而不是HTTPException
- 全局错误AOP处理机制不同,sanic通过添加异常处理函数的方式实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class MyResponse(HTTPResponse): code = 500 message = 'sorry, we made a mistake' error_code = 999 cause = None detail = None
def __init__(self, message=None, code=None, error_code=None, cause=None, detail=None): if code: self.code = code if error_code: self.error_code = error_code if message: self.message = message if cause is not None: self.cause = cause if detail is not None: self.detail = detail super(MyResponse, self).__init__(body=self.get_body(), status=self.code)
def get_body(self): body = dict( message=self.message, code=self.error_code )
if self.cause is not None: body.update(dict(cause=self.cause)) if self.detail is not None: body.update({"detail": self.detail})
return json_dumps(body)
|
至于各种派生的错误类,与flask一致。
1 2 3 4 5
| class Success(MyResponse): code = 200 message = 'OK' local_code = "000" error_code = 99999
|
全局异常处理。
1 2 3 4 5 6
| async def server_error_handler(request, exception): logger.error(msg=traceback.format_exc()) return ServerError(message=repr(exception), cause=traceback.format_exc())
app.error_handler.add(Exception, server_error_handler)
|
发生系统异常后,这里统一使用ServerError返回。ServerError是自己定义的继承自MyResponse的异常类。
1 2 3 4 5
| class ServerError(MyResponse): code = 500 message = 'something happen' local_code = "000" error_code = 99999
|