bigywater.tech
Flask · 102

API 错误响应统一格式

API 出错时应该返回什么格式?怎么让 404、405、400、500 都变成 JSON?蓝图里的错误处理器有什么陷阱?这篇用 test_client 逐个验证每种错误在默认与统一之后的样子。

HTML → JSON
默认错误页是 HTML,统一处理后 7 种错误都变成 JSON
request_id
每个错误响应都带的请求标识,调用方可以传入
蓝图 404
蓝图的 404 处理器接不到路由没匹配的请求

默认的错误响应

实测 · 本机执行输出
  不存在的路径                     → 404 text/html         <!doctype html> <html lang=en> <title>404 Not Found</title> <h1>Not Found</h1> <p>The requested URL was not fo
  abort(404, description=...) → 404 text/html         <!doctype html> <html lang=en> <title>404 Not Found</title> <h1>Not Found</h1> <p>item 0 不存在</p>
  方法不允许                      → 405 text/html         <!doctype html> <html lang=en> <title>405 Method Not Allowed</title> <h1>Method Not Allowed</h1> <p>The method
  未处理异常                      → 500 text/html         <!doctype html> <html lang=en> <title>500 Internal Server Error</title> <h1>Internal Server Error</h1> <p>The 
  非法 JSON                    → 400 text/html         <!doctype html> <html lang=en> <title>400 Bad Request</title> <h1>Bad Request</h1> <p>The browser (or proxy) s

上一篇:Flask 实现 JSON API;下一篇:请求参数校验。

统一成 JSON

实测 · 本机执行输出
  不存在的路径                     → 404 application/json  {"error":{"code":"not_found","message":"The requested URL was not found on the server. If you entered the URL 
  abort(404, description=...) → 404 application/json  {"error":{"code":"not_found","message":"item 0 \u4e0d\u5b58\u5728","request_id":"335f3de9"}}
  方法不允许                      → 405 application/json  {"error":{"code":"method_not_allowed","message":"The method is not allowed for the requested URL.","request_id
  自定义 ApiError 409           → 409 application/json  {"error":{"code":"conflict","current":5,"message":"\u7248\u672c\u51b2\u7a81","request_id":"ff18bc4a"}}
  未处理异常                      → 500 application/json  {"error":{"code":"internal_error","message":"\u670d\u52a1\u5668\u5185\u90e8\u9519\u8bef","request_id":"68df624
  非法 JSON                    → 400 application/json  {"error":{"code":"bad_request","message":"The browser (or proxy) sent a request that this server could not und
  Content-Type 不对            → 415 application/json  {"error":{"code":"unsupported_media_type","message":"Did not attempt to load JSON data because the request Con
  405 响应保留了 Allow 头: OPTIONS, HEAD, GET
  500 的响应里带着调用方传的 request_id: abc-123 | 响应里有没有泄漏异常信息 "hunter2": False

API 与页面共存

实测 · 本机执行输出
  /api/nope                  → 404 application/json  {"error":"Not Found"}
  /page(abort 403)           → 403 text/html         <!doctype html> <html lang=en> <title>403 Forbidden</title> <h1>Forbidden</h1> <p>You don&#39;t have the permi

蓝图里的 404

实测 · 本机执行输出
  蓝图里的视图 abort(404) → {'src': 'blueprint'}
  /api/unknown(路由没匹配)→ {'src': 'app'} (走的是应用级处理器,不是蓝图的)

debug 与测试模式

实测 · 本机执行输出
  默认             → 500 {'error': 'handled', 'type': 'RuntimeError'}
  TESTING=True   → 500 {'error': 'handled', 'type': 'RuntimeError'}
  DEBUG=True     → 500 {'error': 'handled', 'type': 'RuntimeError'}

分步演示

API 错误响应格式
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动
    • 没有验证:真实 HTTP 下的行为(与 test_client 相同,没有差别的预期但未验证)、RFC 9457(Problem Details)格式、多语言 message、异步视图里的错误处理、日志与 Sentry 等错误上报的集成
    京ICP备2026067502号-1京公网安备11010502063487号