FastAPI教程 自定義響應(yīng) - HTML,流,文件和其他

2021-11-08 09:48 更新

FastAPI 默認會使用 JSONResponse 返回響應(yīng)。

你可以通過直接返回 Response 來重載它,參見 直接返回響應(yīng)。

但如果你直接返回 Response,返回數(shù)據(jù)不會自動轉(zhuǎn)換,也不會自動生成文檔(例如,在 HTTP 頭 Content-Type 中包含特定的「媒體類型」作為生成的 OpenAPI 的一部分)。

你還可以在 路徑操作裝飾器 中聲明你想用的 Response。

你從 路徑操作函數(shù) 中返回的內(nèi)容將被放在該 Response 中。

并且如果該 Response 有一個 JSON 媒體類型(application/json),比如使用 JSONResponse 或者 UJSONResponse 的時候,返回的數(shù)據(jù)將使用你在路徑操作裝飾器中聲明的任何 Pydantic 的 response_model 自動轉(zhuǎn)換(和過濾)。

說明

如果你使用不帶有任何媒體類型的響應(yīng)類,F(xiàn)astAPI 認為你的響應(yīng)沒有任何內(nèi)容,所以不會在生成的OpenAPI文檔中記錄響應(yīng)格式。

使用 ORJSONResponse?

例如,如果你需要壓榨性能,你可以安裝并使用 orjson 并將響應(yīng)設(shè)置為 ORJSONResponse。

導(dǎo)入你想要使用的 Response 類(子類)然后在 路徑操作裝飾器 中聲明它。

from fastapi import FastAPI
from fastapi.responses import ORJSONResponse

app = FastAPI()


@app.get("/items/", response_class=ORJSONResponse)
async def read_items():
    return [{"item_id": "Foo"}]

提示

參數(shù) response_class 也會用來定義響應(yīng)的「媒體類型」。

在這個例子中,HTTP 頭的 Content-Type 會被設(shè)置成 application/json。

并且在 OpenAPI 文檔中也會這樣記錄。

小貼士

ORJSONResponse 目前只在 FastAPI 中可用,而在 Starlette 中不可用。

HTML 響應(yīng)

使用 HTMLResponse 來從 FastAPI 中直接返回一個 HTML 響應(yīng)。

  • 導(dǎo)入 HTMLResponse。
  • 將 HTMLResponse 作為你的 路徑操作 的 response_class 參數(shù)傳入。
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>
    """

提示

參數(shù) response_class 也會用來定義響應(yīng)的「媒體類型」。

在這個例子中,HTTP 頭的 Content-Type 會被設(shè)置成 text/html。

并且在 OpenAPI 文檔中也會這樣記錄。

返回一個 Response

正如你在 直接返回響應(yīng) 中了解到的,你也可以通過直接返回響應(yīng)在 路徑操作 中直接重載響應(yīng)。

和上面一樣的例子,返回一個 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)

警告

路徑操作函數(shù) 直接返回的 Response 不會被 OpenAPI 的文檔記錄(比如,Content-Type 不會被文檔記錄),并且在自動化交互文檔中也是不可見的。

提示

當然,實際的 Content-Type 頭,狀態(tài)碼等等,將來自于你返回的 Response 對象。

OpenAPI 中的文檔和重載 Response

如果你想要在函數(shù)內(nèi)重載響應(yīng),但是同時在 OpenAPI 中文檔化「媒體類型」,你可以使用 response_class 參數(shù)并返回一個 Response 對象。

接著 response_class 參數(shù)只會被用來文檔化 OpenAPI 的 路徑操作,你的 Response 用來返回響應(yīng)。

直接返回 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()

在這個例子中,函數(shù) generate_html_response() 已經(jīng)生成并返回 Response 對象而不是在 str 中返回 HTML。

通過返回函數(shù) generate_html_response() 的調(diào)用結(jié)果,你已經(jīng)返回一個重載 FastAPI 默認行為的 Response 對象,

但如果你在 response_class 中也傳入了 HTMLResponse,F(xiàn)astAPI 會知道如何在 OpenAPI 和交互式文檔中使用 text/html 將其文檔化為 HTML。

可用響應(yīng)

這里有一些可用的響應(yīng)。

要記得你可以使用 Response 來返回任何其他東西,甚至創(chuàng)建一個自定義的子類。

技術(shù)細節(jié)

你也可以使用 from starlette.responses import HTMLResponse。

FastAPI 提供了同 fastapi.responses 相同的 starlette.responses 只是為了方便開發(fā)者。但大多數(shù)可用的響應(yīng)都直接來自 Starlette。

Response

其他全部的響應(yīng)都繼承自主類 Response。

你可以直接返回它。

Response 類接受如下參數(shù):

  • content - 一個 str 或者 bytes。
  • status_code - 一個 int 類型的 HTTP 狀態(tài)碼。
  • headers - 一個由字符串組成的 dict。
  • media_type - 一個給出媒體類型的 str,比如 "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

如上文所述,接受文本或字節(jié)并返回 HTML 響應(yīng)。

PlainTextResponse

接受文本或字節(jié)并返回純文本響應(yīng)。

from fastapi import FastAPI
from fastapi.responses import PlainTextResponse

app = FastAPI()


@app.get("/", response_class=PlainTextResponse)
async def main():
    return "Hello World"

JSONResponse

接受數(shù)據(jù)并返回一個 application/json 編碼的響應(yīng)。

如上文所述,這是 FastAPI 中使用的默認響應(yīng)。

ORJSONResponse

如上文所述,ORJSONResponse 是一個使用 orjson 的快速的可選 JSON 響應(yīng)。

UJSONResponse

UJSONResponse 是一個使用 ujson 的可選 JSON 響應(yīng)。

警告

在處理某些邊緣情況時,ujson 不如 Python 的內(nèi)置實現(xiàn)那么謹慎。

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 狀態(tài)代碼(臨時重定向)。

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

采用異步生成器或普通生成器/迭代器,然后流式傳輸響應(yīng)主體。

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")

小貼士

注意在這里,因為我們使用的是不支持 async 和 await 的標準 open(),我們使用普通的 def 聲明了路徑操作。

FileResponse

異步傳輸文件作為響應(yīng)。

與其他響應(yīng)類型相比,接受不同的參數(shù)集進行實例化:

  • path - 要流式傳輸?shù)奈募奈募窂健?/li>
  • headers - 任何自定義響應(yīng)頭,傳入字典類型。
  • media_type - 給出媒體類型的字符串。如果未設(shè)置,則文件名或路徑將用于推斷媒體類型。
  • filename - 如果給出,它將包含在響應(yīng)的 Content-Disposition 中。

文件響應(yīng)將包含適當?shù)?nbsp;Content-Length,Last-Modified 和 ETag 的響應(yīng)頭。

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 在 OpenAPI 中聲明媒體類型和許多其他詳細信息:OpenAPI 中的額外文檔。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號