You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 07:07:04