自定义响应 - HTML、流、文件等¶
FastAPI 默认使用 JSONResponse
返回响应。
正如直接返回响应一章所述,您可以直接返回 Response
覆盖默认响应。
但如果直接返回 Response
,FastAPI 不会自动转换返回数据,也不会自动生成文档(例如,把 HTTP 请求头 Content-Type
中的特定媒体类型添加到 OpenAPI )。
路径操作装饰器可以声明自定义 Response
。
路径操作函数返回的内容会被放到 Response
里。
如果 Response
包含 JSON 媒体类型(application/json
),比如使用 JSONResponse
或 UJSONResponse
时,路径操作装饰器中声明的 Pydantic response_model
会自动转换(和过滤)返回的数据。
笔记
如果使用不带有媒体类型的响应类,FastAPI 会认为响应没有任何内容,不会在生成的 OpenAPI 文档中记录响应格式。
使用 ORJSONResponse
¶
例如,如需压榨性能可以使用 orjson
,并把响应设置为 ORJSONResponse
。
导入要使用的 Response
类或它的子类,然后在路径操作装饰器声明响应类。
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI()
@app.get("/items/", response_class=ORJSONResponse)
async def read_items():
return ORJSONResponse([{"item_id": "Foo"}])
说明
response_class
参数也可以用于定义响应的媒体类型。
本例把 HTTP 请求头的 Content-Type
设置为 application/json
。
并在 OpenAPI 中存档。
提示
ORJSONResponse
目前只能用于 FastAPI,在 Starlette 中不可用。
HTML 响应¶
FastAPI 使用 HTMLResponse
直接返回 HTML 响应。
- 导入
HTMLResponse
- 把
HTMLResponse
传递给路径操作装饰器的response_class
参数
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
说明
response_class
参数也可以用于定义响应的媒体类型。
本例把 HTTP 请求头的 Content-Type
设置为 text/html
。
并在 OpenAPI 中存档。
返回 Response
¶
正如直接返回响应 一章所述,您可以直接返回响应在路径操作中覆盖默认响应。
与上例一样,返回 HTMLResponse
的代码如下:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/items/")
async def read_items():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
警告
OpenAPI 不会存档路径操作函数直接返回的 Response
(比如,Content-Type
),在 API 文档中也看不到。
说明
当然,实际的 Content-Type
请求头、状态码等来自返回的 Response
对象。
OpenAPI 存档和覆盖 Response
¶
如果要在函数内覆盖响应,但同时又要在 OpenAPI 中存档媒体类型,要使用 response_class
参数并返回 Response
对象。
response_class
参数只用于存档 OpenAPI 路径操作,Response
则用来返回响应。
直接返回 HTMLResponse
¶
示例如下:
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
app = FastAPI()
def generate_html_response():
html_content = """
<html>
<head>
<title>Some HTML in here</title>
</head>
<body>
<h1>Look ma! HTML!</h1>
</body>
</html>
"""
return HTMLResponse(content=html_content, status_code=200)
@app.get("/items/", response_class=HTMLResponse)
async def read_items():
return generate_html_response()
本例中,generate_html_response()
函数没有返回 HTML 字符串,而是生成并返回 Response
对象。
generate_html_response()
函数返回的结果已经覆盖了 FastAPI 的默认 Response
。
因为在 response_class
还传入了 HTMLResponse
,因此,FastAPI 知道要在 OpenAPI 和 API 文档中以 text/html
格式将之存档为 HTML。
可用响应¶
下面列出一些可用的响应。
注意,使用 Response
可以返回任何其他对象,甚至创建自定义子类。
技术细节
您也可以使用 from starlette.responses import HTMLResponse
。
FastAPI 的 fastapi.responses
与 starlette.responses
一样, 只是为了方便开发者,但其实绝大多数可用的响应都直接继承自 Starlette。
Response
¶
Response
主类,所有其他响应都继承自这个类。
可直接返回。
Response
的参数如下:
content
-str
或bytes
status_code
-int
类型的 HTTP 状态码headers
- 由字符串组成的字典media_type
- 定义媒体类型的字符串,如"text/html"
FastAPI(其实是 Starlette)自动包含 Content-Length
响应头,还包含基于 media_type
的 Content-Type
响应头,并为文本类型添加字符集。
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/legacy/")
def get_legacy_data():
data = """<?xml version="1.0"?>
<shampoo>
<Header>
Apply shampoo here.
</Header>
<Body>
You'll have to use soap here.
</Body>
</shampoo>
"""
return Response(content=data, media_type="application/xml")
HTMLResponse
¶
如上文所述,接收文本或字节,返回 HTML 响应。
PlainTextResponse
¶
接收文本或字节,返回纯文本响应。
from fastapi import FastAPI
from fastapi.responses import PlainTextResponse
app = FastAPI()
@app.get("/", response_class=PlainTextResponse)
async def main():
return "Hello World"
JSONResponse
¶
接收数据,返回 application/json
编码类型的响应。
如上文所述,这是 FastAPI 的默认响应。
ORJSONResponse
¶
如上文所述,ORJSONResponse
是使用 orjson
的快速 JSON 响应。
UJSONResponse
¶
UJSONResponse
是使用 ujson
的 JSON 响应。
警告
在处理某些边缘情况时,ujson
不如 Python 的内置实现那么谨慎。
from fastapi import FastAPI
from fastapi.responses import UJSONResponse
app = FastAPI()
@app.get("/items/", response_class=UJSONResponse)
async def read_items():
return [{"item_id": "Foo"}]
提示
ORJSONResponse
可能更快。
RedirectResponse
¶
返回 HTTP 重定向。默认使用 307 状态代码(临时重定向)。
from fastapi import FastAPI
from fastapi.responses import RedirectResponse
app = FastAPI()
@app.get("/typer")
async def redirect_typer():
return RedirectResponse("https://typer.tiangolo.com")
StreamingResponse
¶
采用异步生成器或普通生成器/迭代器,然后流式传输响应主体。
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
app = FastAPI()
async def fake_video_streamer():
for i in range(10):
yield b"some fake video bytes"
@app.get("/")
async def main():
return StreamingResponse(fake_video_streamer())
使用 StreamingResponse
处理文件类对象¶
创建生成器函数迭代处理文件类对象(例如,open()
返回的对象)。
使用这种方式,无需实现把文件全部读取到内存里,可以传递生成器函数至 StreamingResponse
,然后返回该响应。
这种方式包括许多与云存储、视频处理等交互的支持库。
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
def main():
def iterfile(): # (1)
with open(some_file_path, mode="rb") as file_like: # (2)
yield from file_like # (3)
return StreamingResponse(iterfile(), media_type="video/mp4")
-
这是生成器函数。因为包含
yield
语句,因此它是生成器函数; -
使用
with
代码块,能确保文件类对象在生成器函数执行完毕后正常关闭。即在它发送完响应之后; -
yield from
告诉函数迭代名为file_like
的对象。然后没迭代一部分,就使用生成器函数生成对应的内容;因此,它是用于在内部把传输生成内容传递给其他对象的生成器函数。
由此,可以把它放在
with
代码块里,这样就能确保完成之后正常关闭。
提示
注意,此处使用的是不支持 async
和 await
的标准 open()
,所以要使用普通函数声明路径操作。
FileResponse
¶
异步传输文件的响应。
与其他响应类型不同,此响应接收不同组合的参数进行实例化:
path
- 流式传输文件的路径headers
- 包含任意自定义响应头的字典media_type
- 媒体类型的字符串。如未设置,则使用文件名或路径推断媒体类型filename
- 如设置了文件名,则会包含在响应的Content-Disposition
中
文件响应包含 Content-Length
、Last-Modified
、ETag
等响应头。
from fastapi import FastAPI
from fastapi.responses import FileResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/")
async def main():
return FileResponse(some_file_path)
还可以使用 response_class
参数:
from fastapi import FastAPI
from fastapi.responses import FileResponse
some_file_path = "large-video-file.mp4"
app = FastAPI()
@app.get("/", response_class=FileResponse)
async def main():
return some_file_path
本例从路径操作函数中直接返回文件路径。
默认响应类¶
创建 FastAPI 类实例或 APIRouter
时能够指定默认使用哪个响应类。
定义默认响应类的参数是 default_response_class
。
下例中,FastAPI 的所有路径操作都默认使用 ORJSONResponse
,不再是 JSONResponse
。
from fastapi import FastAPI
from fastapi.responses import ORJSONResponse
app = FastAPI(default_response_class=ORJSONResponse)
@app.get("/items/")
async def read_items():
return [{"item_id": "Foo"}]
提示
您仍可以像之前那样在路径操作覆盖 response_class
。
附加文档¶
您还可以在 OpenAPI 中使用 response
声明媒体类型和更多详细内容:OpenAPI 附加响应。