Python中tornado框架如何使用抛异常来返回JSON错误响应
最近在写 api 时,对错误响应的感觉处理很别扭。
是 True / False
还是封装一个 result 类。
纠结了会,发现,异常好像很好用。
Python中tornado框架如何使用抛异常来返回JSON错误响应
封装 Result 是最好的
{
“err_code”:
“err_msg”:
“detail”
}
在Tornado里用异常返回JSON错误响应,最直接的方式就是自定义一个HTTP异常类,然后在RequestHandler里raise它,最后在write_error里统一处理。
看这个例子:
import tornado.web
import tornado.ioloop
import json
# 1. 先定义个自定义异常类
class APIError(Exception):
def __init__(self, status_code, error_code, message):
self.status_code = status_code
self.error_code = error_code
self.message = message
super().__init__(self.message)
# 2. 在主Handler里继承并重写write_error
class MainHandler(tornado.web.RequestHandler):
def get(self):
# 模拟业务逻辑出错,直接抛自定义异常
raise APIError(400, "INVALID_REQUEST", "请求参数无效")
def write_error(self, status_code, **kwargs):
# 检查是不是我们的自定义异常
exc_info = kwargs.get('exc_info')
if exc_info:
err = exc_info[1]
if isinstance(err, APIError):
# 如果是APIError,按自定义格式返回JSON
self.set_status(err.status_code)
self.write({
"error": {
"code": err.error_code,
"message": err.message
}
})
return
# 其他异常走默认处理
super().write_error(status_code, **kwargs)
# 3. 应用配置
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
跑起来后访问 http://localhost:8888/,就会返回:
{
"error": {
"code": "INVALID_REQUEST",
"message": "请求参数无效"
}
}
关键点:
APIError类封装了HTTP状态码、错误码和消息write_error是Tornado处理未捕获异常的地方,在这里判断异常类型并返回JSON- 用
isinstance(err, APIError)来识别自定义异常
更工程化的做法是写个BaseHandler,让所有业务Handler都继承它,这样异常处理逻辑就统一了:
class BaseHandler(tornado.web.RequestHandler):
def write_error(self, status_code, **kwargs):
exc_info = kwargs.get('exc_info')
if exc_info:
err = exc_info[1]
if isinstance(err, APIError):
self.set_status(err.status_code)
self.set_header("Content-Type", "application/json")
self.write(json.dumps({
"error": {
"code": err.error_code,
"message": err.message
}
}, ensure_ascii=False))
return
super().write_error(status_code, **kwargs)
class UserHandler(BaseHandler):
def get(self):
user_id = self.get_argument("id")
if not user_id:
raise APIError(400, "MISSING_PARAM", "缺少用户ID参数")
# ... 其他业务逻辑
这样在任何地方 raise APIError,客户端都会收到结构化的JSON错误响应。
简单说就是:自定义异常 + 重写write_error统一处理。
{
“success”:true
“data”:
“message”:error_msg
}
我推荐是两者组合。
如果正常返回的结果直接就是 data 本身
如果是 4XX 或者 5XX,除了错误码之外,定义一个异常的 json 即可,一般是"success": true/fasle,“message” : "xxxx"
tornado 可以自定义 errorhandler 来做到这个
{
“status”:"",
“message”:"",
“description”:"",
“data”:{}
}
我比较喜欢这样的,status 自定义状态码,200 为 success,message 返回相关信息
status code + message

