FastAPI 默认会使用 JSONResponse 返回响应。
你可以通过直接返回 Response 来重载它,参见 直接返回响应
但如果你直接返回 Response,返回数据不会自动转换,也不会自动生成文档(例如,在 HTTP 头 Content-Type 中包含特定的「媒体类型」作为生成的 OpenAPI 的一部分)。
你还可以在 路径操作装饰器 中声明你想用的 Response
你从 路径操作函数 中返回的内容将被放在该 Response 中。
并且如果该 Response 有一个 JSON 媒体类型(application/json),比如使用 JSONResponse 或者 UJSONResponse 的时候,返回的数据将使用你在路径操作装饰器中声明的任何 Pydantic 的 response_model 自动转换(和过滤)。

:::info 说明
如果你使用不带有任何媒体类型的响应类,FastAPI 认为你的响应没有任何内容,所以不会在生成的OpenAPI文档中记录响应格式。 :::

使用 ORJSONResponse

例如,如果你需要压榨性能,你可以安装并使用 orjson 并将响应设置为 ORJSONResponse
导入你想要使用的 Response 类(子类)然后在 路径操作装饰器 中声明它。

  1. from fastapi import FastAPI
  2. from fastapi.responses import ORJSONResponse
  3. app = FastAPI()
  4. @app.get("/items/", response_class=ORJSONResponse)
  5. async def read_items():
  6. return [{"item_id": "Foo"}]


:::info 提示
参数 response_class 也会用来定义响应的「媒体类型」。 :::

在这个例子中,HTTP 头的 Content-Type 会被设置成 application/json
并且在 OpenAPI 文档中也会这样记录。

:::info 小贴士
ORJSONResponse 目前只在 FastAPI 中可用,而在 Starlette 中不可用。 :::

HTML 响应

使用 HTMLResponse 来从 FastAPI 中直接返回一个 HTML 响应。

  • 导入 HTMLResponse
  • HTMLResponse 作为你的 路径操作 的 response_class 参数传入。
    1. from fastapi import FastAPI
    2. from fastapi.responses import HTMLResponse
    3. app = FastAPI()
    4. @app.get("/items/", response_class=HTMLResponse)
    5. async def read_items():
    6. return """
    7. <html>
    8. <head>
    9. <title>Some HTML in here</title>
    10. </head>
    11. <body>
    12. <h1>Look ma! HTML!</h1>
    13. </body>
    14. </html>
    15. """

    :::info 提示
    参数 response_class 也会用来定义响应的「媒体类型」。
    在这个例子中,HTTP 头的 Content-Type 会被设置成 text/html
    并且在 OpenAPI 文档中也会这样记录。 :::

    返回一个 Response

    正如你在 直接返回响应 中了解到的,你也可以通过直接返回响应在 路径操作 中直接重载响应。
    和上面一样的例子,返回一个 HTMLResponse 看起来可能是这样:
    1. from fastapi import FastAPI
    2. from fastapi.responses import HTMLResponse
    3. app = FastAPI()
    4. @app.get("/items/")
    5. async def read_items():
    6. html_content = """
    7. <html>
    8. <head>
    9. <title>Some HTML in here</title>
    10. </head>
    11. <body>
    12. <h1>Look ma! HTML!</h1>
    13. </body>
    14. </html>
    15. """
    16. return HTMLResponse(content=html_content, status_code=200)

    :::warning 警告
    路径操作函数 直接返回的 Response 不会被 OpenAPI 的文档记录(比如,Content-Type 不会被文档记录),并且在自动化交互文档中也是不可见的。 :::
    :::info 提示
    当然,实际的 Content-Type 头,状态码等等,将来自于你返回的 Response 对象。 :::

    OpenAPI 中的文档和重载 Response

    如果你想要在函数内重载响应,但是同时在 OpenAPI 中文档化「媒体类型」,你可以使用 response_class 参数并返回一个 Response 对象。
    接着 response_class 参数只会被用来文档化 OpenAPI 的 路径操作,你的 Response 用来返回响应。

    直接返回 HTMLResponse

    比如像这样:
    1. from fastapi import FastAPI
    2. from fastapi.responses import HTMLResponse
    3. app = FastAPI()
    4. def generate_html_response():
    5. html_content = """
    6. <html>
    7. <head>
    8. <title>Some HTML in here</title>
    9. </head>
    10. <body>
    11. <h1>Look ma! HTML!</h1>
    12. </body>
    13. </html>
    14. """
    15. return HTMLResponse(content=html_content, status_code=200)
    16. @app.get("/items/", response_class=HTMLResponse)
    17. async def read_items():
    18. return generate_html_response()
    在这个例子中,函数 generate_html_response() 已经生成并返回 Response 对象而不是在 str 中返回 HTML。
    通过返回函数 generate_html_response() 的调用结果,你已经返回一个重载 FastAPI 默认行为的 Response 对象,
    但如果你在 response_class 中也传入了 HTMLResponseFastAPI 会知道如何在 OpenAPI 和交互式文档中使用 text/html 将其文档化为 HTML。
    自定义响应 - HTML,流,文件和其他 - 图1

    可用响应

    这里有一些可用的响应。
    要记得你可以使用 Response 来返回任何其他东西,甚至创建一个自定义的子类。

:::info 技术细节
你也可以使用 from starlette.responses import HTMLResponse
FastAPI 提供了同 fastapi.responses 相同的 starlette.responses 只是为了方便开发者。但大多数可用的响应都直接来自 Starlette。** :::

Response

其他全部的响应都继承自主类 Response
你可以直接返回它。
Response 类接受如下参数:

  • content - 一个 str 或者 bytes
  • status_code - 一个 int 类型的 HTTP 状态码。
  • headers - 一个由字符串组成的 dict
  • media_type - 一个给出媒体类型的 str,比如 "text/html"

FastAPI(实际上是 Starlette)将自动包含 Content-Length 的头。它还将包含一个基于 media_type 的 Content-Type 头,并为文本类型附加一个字符集。

  1. from fastapi import FastAPI, Response
  2. app = FastAPI()
  3. @app.get("/legacy/")
  4. def get_legacy_data():
  5. data = """<?xml version="1.0"?>
  6. <shampoo>
  7. <Header>
  8. Apply shampoo here.
  9. </Header>
  10. <Body>
  11. You'll have to use soap here.
  12. </Body>
  13. </shampoo>
  14. """
  15. return Response(content=data, media_type="application/xml")

HTMLResponse

如上文所述,接受文本或字节并返回 HTML 响应。

PlainTextResponse

接受文本或字节并返回纯文本响应。

  1. from fastapi import FastAPI
  2. from fastapi.responses import PlainTextResponse
  3. app = FastAPI()
  4. @app.get("/", response_class=PlainTextResponse)
  5. async def main():
  6. return "Hello World"

JSONResponse

接受数据并返回一个 application/json 编码的响应。
如上文所述,这是 FastAPI 中使用的默认响应。

ORJSONResponse

如上文所述,ORJSONResponse 是一个使用 orjson 的快速的可选 JSON 响应。

UJSONResponse

UJSONResponse 是一个使用 ujson 的可选 JSON 响应。

:::warning **
在处理某些边缘情况时,ujson 不如 Python 的内置实现那么谨慎。 :::

  1. from fastapi import FastAPI
  2. from fastapi.responses import UJSONResponse
  3. app = FastAPI()
  4. @app.get("/items/", response_class=UJSONResponse)
  5. async def read_items():
  6. return [{"item_id": "Foo"}]


:::info 小贴士
ORJSONResponse 可能是一个更快的选择。 :::

RedirectResponse

返回 HTTP 重定向。默认情况下使用 307 状态代码(临时重定向)。

  1. from fastapi import FastAPI
  2. from fastapi.responses import RedirectResponse
  3. app = FastAPI()
  4. @app.get("/typer")
  5. async def read_typer():
  6. return RedirectResponse("https://typer.tiangolo.com")

StreamingResponse

采用异步生成器或普通生成器/迭代器,然后流式传输响应主体。

  1. from fastapi import FastAPI
  2. from fastapi.responses import StreamingResponse
  3. app = FastAPI()
  4. async def fake_video_streamer():
  5. for i in range(10):
  6. yield b"some fake video bytes"
  7. @app.get("/")
  8. async def main():
  9. return StreamingResponse(fake_video_streamer())

对类似文件的对象使用 StreamingResponse

如果您有类似文件的对象(例如,由 open() 返回的对象),则可以在 StreamingResponse 中将其返回。
包括许多与云存储,视频处理等交互的库。

  1. from fastapi import FastAPI
  2. from fastapi.responses import StreamingResponse
  3. some_file_path = "large-video-file.mp4"
  4. app = FastAPI()
  5. @app.get("/")
  6. def main():
  7. file_like = open(some_file_path, mode="rb")
  8. return StreamingResponse(file_like, media_type="video/mp4")


:::info 小贴士
注意在这里,因为我们使用的是不支持 asyncawait 的标准 open(),我们使用普通的 def 声明了路径操作。 :::

FileResponse

异步传输文件作为响应。
与其他响应类型相比,接受不同的参数集进行实例化:

  • path - 要流式传输的文件的文件路径。
  • headers - 任何自定义响应头,传入字典类型。
  • media_type - 给出媒体类型的字符串。如果未设置,则文件名或路径将用于推断媒体类型。
  • filename - 如果给出,它将包含在响应的 Content-Disposition 中。

文件响应将包含适当的 Content-LengthLast-ModifiedETag 的响应头。

  1. from fastapi import FastAPI
  2. from fastapi.responses import FileResponse
  3. some_file_path = "large-video-file.mp4"
  4. app = FastAPI()
  5. @app.get("/")
  6. async def main():
  7. return FileResponse(some_file_path)

额外文档

您还可以使用 response 在 OpenAPI 中声明媒体类型和许多其他详细信息:OpenAPI 中的额外文档