FastAPI猜字谜实战(6):日志与异常

这是系列的第六篇。前面几篇我一路靠 print 走过来,能跑是能跑,但真出了错,浏览器那边一片空白,控制台一堆原始堆栈,看着头大。这一篇我把调试输出正规化,再给整个后端加个兜底。

一、print 用多了,我自己都嫌乱

一开始我在每个接口里写几句 print,看看走到哪一步了。功能少还行,等接口多起来,我发现问题很大:

  • 没时间戳,不知道是哪一秒出的事;

  • 没级别,不知道是普通信息还是严重错误;

  • 不知道是哪一行打的,出了事翻半天找不到源头;

  • 没法按需关闭,正式跑起来了一堆调试信息还在那刷屏。

所以我决定,换成正规的 logging。

二、一行配置,日志立刻像样了

我在文件顶部配一次,之后全用 logging.info:

import logging

logging.basicConfig(

level=logging.INFO,

format="%(asctime)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s",

)

这个 format 是我特意挑的,打出来一条日志,自带时间、级别、文件名、行号、内容 五样东西。之前那些 print 我全替换成了 logging.info,写法没变、只是换了个名字,可输出质量完全是两个世界。

级别设成 INFO,是为了平时开发能看见普通信息。想安静的时候,我可以临时把它调到 ERROR,那些 info 就不刷了,只留重要的。这就是 print 给不了我的开关。

三、顺手关掉访问日志的刷屏

配好 logging 后,我还发现一个很吵的东西:uvicorn 每收到一个请求,就在控制台打一行 GET /... 200 OK 这种访问日志。开发时我压根不需要它,反而盖住了我自己的业务日志。

我在启动时加了个参数把它关了:

uvicorn.run(app, host="0.0.0.0", port=8000, access_log=False)

关掉之后,那些每条请求的访问行没了,控制台清爽很多,只剩启动信息和我的 logging 输出。

四、真正让我头疼的是报错

日志规整了,可还有个更大的问题。比如详情接口去读一个根本不存在的会话文件,open 直接抛异常。没处理的话会怎样?

前端 fetch 收到的是一个残缺的、甚至空白的响应,页面上什么提示都没有,玩家一脸懵。而我控制台里蹦出来的,是一整段原生的 traceback,又长又难看。

我要的是:不管后端哪里出错,都别把内部堆栈甩给前端,而是老老实实返回一个统一的错误 JSON,同时把真正的错误给我记到日志里。

五、一个全局异常处理器兜住所有

FastAPI 给了我这个能力,就是异常处理器。我注册一个兜底的,捕获所有没被处理的异常:

from fastapi import Request

from fastapi.responses import JSONResponse

@app.exception_handler(Exception)

def handler_exception(request: Request, exception: Exception) -> JSONResponse:

把出事的网址和错误信息记到日志里,只有我开发者看得到

logging.error(f"处理异常:请求路径 {request.url},错误信息:{exception}")

给前端返回规范的 JSON 三件套

return JSONResponse(

status_code=500,

content={"code": 500, "message": "服务器内部错误请联系管理员", "data": None},

)

它的逻辑是:一旦哪个接口抛了我没接住的异常,就全汇到这来。我用 logging.error 记下来,然后返回一个 JSONResponse,状态码 500,内容却还是我那个 code / message / data 三件套格式。

这样前端永远拿到的都是规范的 JSON,它能认出 code 不是 200、然后把 message 显示给玩家,页面不会崩、不会一片空白。

六、验证:故意读一个不存在的会话

我起了服务,专门去访问一个乱写的 id,比如 /api/sessions/not-exist-123。那个文件根本不存在,接口里的 open 必然抛异常。

结果符合预期:

  • 后端 :我这边控制台看到一条 ERROR 级日志,带着请求路径和具体错误。

  • 前端 :收到的却是干净的 {code: 500, message: "服务器内部错误...", data: null},不是半截 HTML,也不是空白。

一点小说明:即使有了这个处理器,uvicorn 控制台还是会额外打一段原始堆栈,那是它自带的行为,我的处理器管不着。但它不影响前端拿到的那个干净 JSON,所以不用管它。

相关推荐
Cooper251 小时前
DDC 命令成功但屏幕不动:用 gamma 表重做亮度映射
python·mac
师夷长技以自愈2 小时前
手搓 AI Agent 第 7 篇:菜做砸了别硬炒——错误分类 + 双账本熔断
人工智能·python
用户956256254292 小时前
15 分钟社媒简报 Agent:我只用了搜索和模型两步
python·api
Dumbness2 小时前
关键词回复里写了 {订单号},群机器人整条消息都炸了
python·微信
调接口的阿光2 小时前
调用对话接口时输出被截断怎么办:先看 finish_reason,再决定是续写一次、缩小范围,还是换成更短的格式(Python)
人工智能·python
Cooper252 小时前
单文件 Flask 跑通微信服务器校验:先跑通再谈工程化
python·flask
Cooper252 小时前
三源热榜去重加 AI 摘要:URL 唯一键踩出的三个坑
前端·python
用户4019925568612 小时前
多源异构 B2B 公开需求信号去重与企业实体证据链存储设计(64-bit SimHash 分桶 + Jaccard)
python
aifannihao3 小时前
GitHub Actions 锁文件实测:6 个 uses 只锁住 2 个
python·ci/cd·标准库·供应链安全·github actions
2601_967980113 小时前
使用gensim处理文本(1)语料库与词向量空间
python·自然语言处理·gensim·词向量·文本分析