跳到主要内容

响应报文

前言

FastAPI 默认返回 JSON,也支持 HTML、纯文本、重定向、文件流、字节流等其它响应类型。本章整理响应状态码、response_model 以及各类 Response 的用法。

指定响应状态码

from fastapi import status


@app.post("/status_code", status_code=status.HTTP_200_OK)
def status_attribute():
return {"status_code": status.HTTP_200_OK}

使用 response_model 定义响应内容

response_model 用于声明接口的响应结构,FastAPI 会据此过滤、校验并生成 OpenAPI 文档。

from pydantic import BaseModel


class ReqBody1(BaseModel):
username: str
password: str
age: int
address: str | None = None


class RespBody1(BaseModel):
username: str
age: int
address: str | None = None


@router.post("/resptest1", summary="响应模型测试1", response_model=RespBody1)
def resptest1(req: ReqBody1):
return req


# 如果只是去掉几个字段,用 response_model_exclude 更方便,不需要额外定义类
@router.post(
"/resptest2",
response_model=ReqBody1,
response_model_exclude={"password"},
)
def resptest2(req: ReqBody1):
return req

测试响应:

curl -X 'POST' \
'http://127.0.0.1:8000/jsonbody/resptest1' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"username": "string",
"password": "string",
"age": 0,
"address": "string"
}'

# {"username":"string","age":0,"address":"string"}

其它相关参数(完整列表见 定义路由):

  • response_model_include={"a", "b"}:只返回指定字段。
  • response_model_exclude_unset=True:不返回未赋值的字段。
  • response_model_exclude_defaults=True:不返回使用了默认值的字段。
  • response_model_exclude_none=True:不返回值为 None 的字段。

Response 类型

Response 是所有响应类的基类,常见子类:

  • JSONResponseORJSONResponse:JSON 格式(ORJSONResponse 基于 orjson,性能更好,需安装 orjson)。
  • HTMLResponse:HTML 文本。
  • PlainTextResponse:纯文本。
  • RedirectResponse:重定向。
  • StreamingResponse:字节流/文本流(SSE、视频流等)。
  • FileResponse:文件下载。

直接返回字典时,FastAPI 默认使用 JSONResponse 序列化。

JSONResponse

from fastapi.responses import JSONResponse


@app.post("/")
async def index():
return JSONResponse(
status_code=404, content={"code": 0, "msg": "ok", "data": None}
)

HTMLResponse

from fastapi.responses import HTMLResponse


@app.get("/html", response_class=HTMLResponse)
async def html_page():
return """
<html>
<head><title>FastAPI</title></head>
<body><h1>Hello HTML</h1></body>
</html>
"""

PlainTextResponse

from fastapi.responses import PlainTextResponse


@app.get("/resptext", summary="字符串响应测试")
def resptext():
return PlainTextResponse(status_code=200, content="hello world")

RedirectResponse

from fastapi.responses import RedirectResponse


@router.get("/respredirect1", summary="内部路由重定向")
def respredirect1():
return RedirectResponse("/resptext", status_code=302)


@router.get("/respredirect2", summary="外部重定向")
def respredirect2():
return RedirectResponse("https://baidu.com", status_code=302)
  • 301:永久重定向
  • 302:临时重定向

StreamingResponse

流式响应适合逐块输出内容,如 SSE、大文件、视频流。示例:模拟文本流式输出:

import asyncio

from fastapi.responses import StreamingResponse


async def text_stream():
for i in range(5):
yield f"chunk {i}\n"
await asyncio.sleep(0.5)


@router.get("/stream")
async def stream_text():
return StreamingResponse(text_stream(), media_type="text/plain")
提示

SSE 场景一般使用 media_type="text/event-stream",完整示例见 补充:用 FastAPI 和 Streamlit 实现 ChatBot

FileResponse 与 Excel 下载

FileResponse 一般用于文件下载:

from fastapi.responses import FileResponse


@router.get("/respdownload", summary="下载测试")
async def respdownload():
return FileResponse(path="./test.jpg", filename="test.jpg")

生成并下载 Excel 文件(需安装 openpyxl):

python -m pip install openpyxl
from datetime import datetime
from io import BytesIO

from fastapi import APIRouter
from fastapi.responses import StreamingResponse
from openpyxl import Workbook

router = APIRouter(prefix="/excel", tags=["excel"])


@router.get("/download")
def download_excel():
wb = Workbook()
ws = wb.active
ws.title = "Sheet1"
ws.append(["姓名", "年龄", "城市"])
ws.append(["张三", 18, "北京"])
ws.append(["李四", 22, "上海"])

buf = BytesIO()
wb.save(buf)
buf.seek(0)

filename = f"users_{datetime.now().strftime('%Y%m%d%H%M%S')}.xlsx"
return StreamingResponse(
buf,
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={"Content-Disposition": f'attachment; filename="{filename}"'},
)
提示

BytesIO 直接在内存中生成文件,避免把临时文件写到磁盘;Content-Disposition 指定下载文件名。文件较大时可用 FileResponse(path=...) 指向已生成的文件,并配合 background=BackgroundTask(os.remove, path) 在响应后清理临时文件(见 后台任务)。