【学习记录】FastAPI 响应类型完全指南:从 JSON 到流式响应、异常处理与输出模型
在构建 Web API 时,不仅需要接收参数,还需要灵活控制返回给客户端的响应格式。FastAPI 提供了丰富的响应类型支持,包括 JSON、HTML、纯文本、文件、流式数据、重定向等,还可以通过
response_model自动验证和序列化输出,并通过HTTPException规范错误响应。本文系统讲解 FastAPI 中所有常用的响应类型及其使用场景,提供完整可运行的代码示例,助你构建专业、健壮的 API。
📌 目录
- JSONResponse(默认行为)
- [HTMLResponse:返回 HTML 页面](#HTMLResponse:返回 HTML 页面)
- PlainTextResponse:纯文本响应
- FileResponse:文件下载与预览
- StreamingResponse:流式传输大文件或实时数据
- RedirectResponse:重定向
- 在装饰器中指定响应类型(
response_class) - 直接返回响应对象
- [自定义输出模型:
response_model自动验证与文档生成](#自定义输出模型:response_model 自动验证与文档生成) - [异常响应处理:
HTTPException与自定义异常处理器](#异常响应处理:HTTPException 与自定义异常处理器) - 完整可运行示例
- 总结与最佳实践
一、JSONResponse(默认行为)
FastAPI 默认使用 JSONResponse 将返回的字典或 Pydantic 模型自动转换为 JSON 格式,并设置 Content-Type: application/json。你无需显式导入,直接返回 Python 字典即可。
python
from fastapi import FastAPI
app = FastAPI()
@app.get("/json-default")
def json_default():
return {"message": "This is automatically converted to JSONResponse"}
也可以显式使用 JSONResponse,以便自定义状态码或其他响应头:
python
from fastapi.responses import JSONResponse
@app.get("/json-explicit")
def json_explicit():
return JSONResponse(content={"message": "Explicit JSONResponse"}, status_code=201)
二、HTMLResponse:返回 HTML 页面
使用 HTMLResponse 可以返回 HTML 内容,浏览器会将其渲染为网页。
python
from fastapi.responses import HTMLResponse
@app.get("/html", response_class=HTMLResponse)
def html_response():
html_content = """
<html>
<head><title>FastAPI HTML</title></head>
<body>
<h1>Hello, FastAPI!</h1>
<p>This is an HTML response.</p>
</body>
</html>
"""
return html_content
三、PlainTextResponse:纯文本响应
当需要返回纯文本(如日志、配置内容)时,使用 PlainTextResponse,避免框架自动添加额外格式。
python
from fastapi.responses import PlainTextResponse
@app.get("/text", response_class=PlainTextResponse)
def text_response():
return "This is plain text response."
四、FileResponse:文件下载与预览
FileResponse 可以返回服务器上的文件,自动推断 Content-Type(如 image/jpeg、application/pdf),支持设置下载文件名。
python
from fastapi.responses import FileResponse
@app.get("/file")
def file_response():
# 假设当前目录下存在 example.pdf
return FileResponse("example.pdf", filename="document.pdf", media_type="application/pdf")
filename:建议浏览器下载时的文件名。media_type:可手动指定,不指定则自动推断。
五、StreamingResponse:流式传输大文件或实时数据
当文件很大或需要边生成边发送数据(如实时日志、视频流、AI 生成流)时,使用 StreamingResponse。它接受一个异步生成器或迭代器,逐块发送数据。
python
from fastapi.responses import StreamingResponse
import asyncio
async def data_generator():
for i in range(5):
yield f"Chunk {i}\n".encode()
await asyncio.sleep(1)
@app.get("/stream")
async def streaming_response():
return StreamingResponse(data_generator(), media_type="text/plain")
六、RedirectResponse:重定向
RedirectResponse 用于将客户端重定向到另一个 URL,支持永久(301)或临时(302)重定向。
python
from fastapi.responses import RedirectResponse
@app.get("/redirect")
def redirect():
return RedirectResponse(url="https://fastapi.tiangolo.com", status_code=302)
七、在装饰器中指定响应类型(response_class)
无需在函数内部返回响应对象,直接在装饰器中使用 response_class 参数即可指定该端点的默认响应类型。函数体内返回对应格式的内容(字符串、字典等),FastAPI 会自动封装。
python
@app.get("/html-decorator", response_class=HTMLResponse)
def html_decorator():
# 直接返回 HTML 字符串,FastAPI 会用 HTMLResponse 包装
return "<h1>Title</h1><p>This HTML is from decorator.</p>"
八、直接返回响应对象
在路径操作函数中直接返回 Response 子类的实例,可以完全控制响应内容、状态码和头部。
python
@app.get("/return-obj")
def return_response_object():
return HTMLResponse(content="<h2>Returned as HTMLResponse object</h2>", status_code=200)
九、自定义输出模型:response_model 自动验证与文档生成
通过 response_model 参数指定一个 Pydantic 模型,FastAPI 会:
- 自动验证返回值是否符合模型定义(类型、必填字段等)
- 序列化模型实例为 JSON
- 在 OpenAPI 文档中生成精确的响应 schema
python
from pydantic import BaseModel
from typing import List
class Item(BaseModel):
name: str
price: float
@app.get("/items/{item_id}", response_model=Item)
def get_item(item_id: int):
# 实际可能从数据库查询
return Item(name="Apple", price=1.99)
@app.get("/items", response_model=List[Item])
def list_items():
return [Item(name="Apple", price=1.99), Item(name="Orange", price=2.49)]
注意 :返回的数据会自动排除模型中未定义的字段(如内部字段 _id),起到输出过滤作用。
十、异常响应处理:HTTPException 与自定义异常处理器
10.1 抛出标准 HTTP 异常
使用 HTTPException 可以返回标准 HTTP 错误码和错误信息,FastAPI 会自动生成对应的 JSON 响应。
python
from fastapi import HTTPException
@app.get("/secure/{code}")
def secure_endpoint(code: int):
if code != 42:
raise HTTPException(status_code=403, detail="Invalid access code")
return {"message": "Welcome"}
10.2 自定义异常处理器
可以覆盖默认的异常响应格式,例如统一错误返回格式。
python
from fastapi import Request
from fastapi.responses import JSONResponse
@app.exception_handler(403)
async def forbidden_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(status_code=403, content={"error": "Access forbidden", "detail": exc.detail})
十一、完整可运行示例
将上述所有片段整合到一个文件中(main.py),启动服务后即可测试。
python
from fastapi import FastAPI, HTTPException
from fastapi.responses import (
JSONResponse, HTMLResponse, PlainTextResponse,
FileResponse, StreamingResponse, RedirectResponse
)
from pydantic import BaseModel
from typing import List
import asyncio
app = FastAPI(title="响应类型演示", description="展示各种响应方式")
# 1. JSONResponse(默认)
@app.get("/json-default")
def json_default():
return {"message": "JSON default"}
# 2. HTMLResponse
@app.get("/html", response_class=HTMLResponse)
def html_response():
return "<html><body><h1>HTML</h1></body></html>"
# 3. PlainTextResponse
@app.get("/text", response_class=PlainTextResponse)
def text_response():
return "Plain text"
# 4. FileResponse(需要存在 example.pdf)
@app.get("/file")
def file_response():
return FileResponse("example.pdf", filename="doc.pdf")
# 5. StreamingResponse
async def stream_gen():
for i in range(3):
yield f"data: {i}\n".encode()
await asyncio.sleep(0.5)
@app.get("/stream")
async def streaming():
return StreamingResponse(stream_gen(), media_type="text/plain")
# 6. RedirectResponse
@app.get("/redirect")
def redirect():
return RedirectResponse("https://fastapi.tiangolo.com")
# 7. 装饰器指定响应类型(已由 html 端点展示)
# 8. 直接返回响应对象
@app.get("/return-obj")
def return_obj():
return HTMLResponse("<h2>Direct Response Object</h2>")
# 9. response_model 自定义输出格式
class Item(BaseModel):
name: str
price: float
@app.get("/items/{item_id}", response_model=Item)
def get_item(item_id: int):
return Item(name="Apple", price=1.99)
@app.get("/items", response_model=List[Item])
def list_items():
return [Item(name="Apple", price=1.99), Item(name="Orange", price=2.49)]
# 10. HTTPException
@app.get("/secure/{code}")
def secure(code: int):
if code != 42:
raise HTTPException(status_code=403, detail="Invalid code")
return {"message": "OK"}
# 自定义异常处理器(可选)
@app.exception_handler(403)
async def custom_403(request, exc):
return JSONResponse(status_code=403, content={"detail": "Forbidden custom message"})
启动服务:
bash
uvicorn main:app --reload
访问测试:
http://127.0.0.1:8000/json-defaulthttp://127.0.0.1:8000/htmlhttp://127.0.0.1:8000/texthttp://127.0.0.1:8000/file(需文件存在)http://127.0.0.1:8000/streamhttp://127.0.0.1:8000/redirecthttp://127.0.0.1:8000/return-objhttp://127.0.0.1:8000/items/1http://127.0.0.1:8000/itemshttp://127.0.0.1:8000/secure/123(返回 403)
十二、总结与最佳实践
| 响应类型 | 适用场景 | 关键点 |
|---|---|---|
| JSONResponse | REST API 默认格式 | 直接返回字典或 Pydantic 模型 |
| HTMLResponse | 返回网页、富文本内容 | 可使用 response_class=HTMLResponse |
| PlainTextResponse | 纯文本(日志、配置) | 避免额外格式包装 |
| FileResponse | 文件下载、图片预览 | 自动识别 Content-Type |
| StreamingResponse | 大文件、实时流、SSE | 使用异步生成器 |
| RedirectResponse | 跳转到其他 URL | 可设置永久/临时重定向 |
| response_model | 输出格式约束、自动文档 | 推荐用于所有公开 API |
| HTTPException | 统一错误响应 | 可自定义异常处理器 |
核心建议:
- ✅ 默认使用 JSONResponse 返回结构化数据。
- ✅ 为所有公开端点声明
response_model,即使返回字典也建议定义模型。 - ✅ 对于大文件或流式数据,优先使用
StreamingResponse避免内存溢出。 - ✅ 错误处理统一使用
HTTPException,并考虑全局异常处理器。 - ✅ 利用
response_class简化装饰器代码,使函数体更简洁。
通过灵活运用 FastAPI 的响应类型,你可以轻松构建出功能丰富、文档完善、健壮可维护的 Web API。