Python中tornado框架如何使用抛异常来返回JSON错误响应

最近在写 api 时,对错误响应的感觉处理很别扭。

是 True / False

还是封装一个 result 类。

纠结了会,发现,异常好像很好用。
Python中tornado框架如何使用抛异常来返回JSON错误响应

6 回复

封装 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

回到顶部