FastAPI返回FileResponse时出现UnicodeDecodeError错误求助
问题分析
报错根源不在FileResponse的逻辑,而是你的自定义响应日志中间件(response_logger.py)在处理二进制文件响应时出错:中间件里尝试用utf-8解码二进制响应体(比如图片的字节流),而二进制文件(如PNG的开头字节是0x89)不符合utf-8编码规则,导致解码失败。
从报错栈可以明确看到错误行:
response_info.body += body.decode("utf8")
解决方法
针对日志中间件的问题,提供三种修复方案:
方案1:跳过二进制响应的内容日志
在日志中间件里判断响应的Content-Type,如果是二进制类型(如图片、流媒体等),只记录长度而非内容:
# 修改response_logger.py中的_logging_send函数 async def _logging_send(self, message): if message["type"] == "http.response.body": body = message.get("body", b"") # 从响应头获取Content-Type content_type = "" for header_name, header_value in message.get("headers", []): if header_name.lower() == b"content-type": content_type = header_value.decode("utf-8") break # 仅处理文本/JSON类型的响应体,二进制类型跳过解码 if content_type.startswith("text/") or content_type == "application/json": response_info.body += body.decode("utf8") else: response_info.body = f"<二进制数据,长度:{len(body)}>" await self.send(message)
方案2:用Base64编码二进制内容后记录
如果需要完整记录二进制内容,可转成Base64字符串避免解码错误:
import base64 # 修改response_logger.py中的_logging_send函数 async def _logging_send(self, message): if message["type"] == "http.response.body": body = message.get("body", b"") try: response_info.body += body.decode("utf8") except UnicodeDecodeError: # 二进制内容转Base64字符串存储 response_info.body += f"<二进制数据Base64编码:{base64.b64encode(body).decode('utf8')}>" await self.send(message)
方案3:路由级别排除日志中间件
如果不想修改中间件代码,可以让静态文件路由跳过日志中间件:
# 在注册日志中间件时添加路由判断 @app.middleware("http") async def response_logger_middleware(request: Request, call_next): # 跳过静态文件路由的日志处理 if request.url.path.startswith("/static/"): return await call_next(request) # 原有日志逻辑... response = await call_next(request) # ... return response
代码优化建议
你的FileResponse代码本身没问题,可做两处规范优化:
- 函数返回类型标注改为
FileResponse(而非None),更符合类型提示规范:
def serve_image(filename: str) -> FileResponse:
- 错误提示里的拼写错误:
"File not fount"改为"File not found"
内容的提问来源于stack exchange,提问作者FAHAD SIDDIQUI
相关产品推荐
相关产品推荐

