1. FastAPI高級(jí)教程(一)

        共 8262字,需瀏覽 17分鐘

         ·

        2024-08-05 21:23

        本文將會(huì)介紹FastAPI中的高級(jí)使用技巧,包括中間件、后臺(tái)任務(wù)、請(qǐng)求前/后、生命周期等。

        歡迎關(guān)注我的公眾號(hào)NLP奇幻之旅,原創(chuàng)技術(shù)文章第一時(shí)間推送。

        歡迎關(guān)注我的知識(shí)星球“自然語(yǔ)言處理奇幻之旅”,筆者正在努力構(gòu)建自己的技術(shù)社區(qū)。

        本文將會(huì)介紹FastAPI中的高級(jí)使用技巧,如下:

        • 中間件(middleware)

        • 后臺(tái)任務(wù)(BackgroundTask)

        • 請(qǐng)求前/后(before or after request)

        • 生命周期(lifespan)

        這些技巧將會(huì)使我們更加充分地利用FastAPI的性能,同時(shí)提升服務(wù)的穩(wěn)定性,使項(xiàng)目更健壯、優(yōu)雅,代碼結(jié)構(gòu)更加清晰。

        中間件(middleware)

        FastAPI中,中間件是用于在處理請(qǐng)求和生成響應(yīng)之間執(zhí)行代碼的組件。中間件可以用于各種任務(wù),例如日志記錄、請(qǐng)求和響應(yīng)的修改、身份驗(yàn)證、跨域資源共享 (CORS) 等。

        中間件介紹

        "中間件"是一個(gè)函數(shù),它在每個(gè)請(qǐng)求被特定的路徑操作處理之前,以及在每個(gè)響應(yīng)返回之前工作。

        • 它接收你的應(yīng)用程序的每一個(gè)請(qǐng)求.

        • 然后它可以對(duì)這個(gè)請(qǐng)求做一些事情或者執(zhí)行任何需要的代碼.

        • 然后它將請(qǐng)求傳遞給應(yīng)用程序的其他部分 (通過(guò)某種路徑操作).

        • 然后它獲取應(yīng)用程序生產(chǎn)的響應(yīng) (通過(guò)某種路徑操作).

        • 它可以對(duì)該響應(yīng)做些什么或者執(zhí)行任何需要的代碼.

        • 然后它返回這個(gè)響應(yīng).

        創(chuàng)建中間件

        要?jiǎng)?chuàng)建中間件你可以在函數(shù)的頂部使用裝飾器 @app.middleware("http").

        中間件參數(shù)接收如下參數(shù):

        • request

        • 一個(gè)函數(shù)call_next, 它將接收 request 作為參數(shù).

        1. 這個(gè)函數(shù)將request傳遞給相應(yīng)的 路徑操作.

        2. 然后它將返回由相應(yīng)的路徑操作生成的response.

        • 然后你可以在返回response前進(jìn)一步修改它.

        # -*- coding: utf-8 -*-
        import time
        import random
        from fastapi import FastAPI, Request

        app = FastAPI()


        @app.middleware("http")
        async def add_process_time_header(request: Request, call_next):
            start_time = time.time()
            response = await call_next(request)
            process_time = time.time() - start_time
            response.headers["X-Process-Time"] = str(process_time)
            return response


        @app.get("/")
        async def read_root():
            time.sleep(random.random())
            return {"message""Hello, World!"}

        if __name__ == "__main__":
            import uvicorn
            uvicorn.run(app, host="0.0.0.0", port=18000)

        注: 用'X-' 前綴添加專(zhuān)有自定義請(qǐng)求頭。

        響應(yīng)體的頭部中新增x-process-time參數(shù)

        其它實(shí)現(xiàn)方法

        也可以用下面的Python代碼實(shí)現(xiàn)中間件:

        # -*- coding: utf-8 -*-
        import time
        import random
        from fastapi import FastAPI, Request
        from starlette.middleware.base import BaseHTTPMiddleware

        app = FastAPI()


        class TimingMiddleware(BaseHTTPMiddleware):
            async def dispatch(self, request: Request, call_next):
                start_time = time.time()
                response = await call_next(request)
                process_time = time.time() - start_time
                response.headers["X-Process-Time"] = str(process_time)
                print(f"Request processed in {process_time} seconds")
                return response


        app.add_middleware(TimingMiddleware)


        @app.get("/")
        async def read_root():
            time.sleep(random.random())
            return {"message""Hello, World!"}

        if __name__ == "__main__":
            import uvicorn
            uvicorn.run(app, host="0.0.0.0", port=18000)

        后臺(tái)任務(wù)(BackgroundTask)

        你可以定義在返回響應(yīng)后運(yùn)行的后臺(tái)任務(wù)。這對(duì)需要在請(qǐng)求之后執(zhí)行的操作很有用,但客戶(hù)端不必在接收響應(yīng)之前等待操作完成。下面是一些例子:

        • 執(zhí)行操作后發(fā)送的電子郵件通知:

          • 由于連接到電子郵件服務(wù)器并發(fā)送電子郵件往往很“慢”(幾秒鐘),您可以立即返回響應(yīng)并在后臺(tái)發(fā)送電子郵件通知。

        • 處理數(shù)據(jù):

          • 例如,假設(shè)您收到的文件必須經(jīng)過(guò)一個(gè)緩慢的過(guò)程,您可以返回一個(gè)"Accepted"(HTTP 202)響應(yīng)并在后臺(tái)處理它。

        示例Python實(shí)現(xiàn)函數(shù):

        # -*- coding: utf-8 -*-
        from fastapi import BackgroundTasks, FastAPI

        app = FastAPI()


        def write_notification(email: str, message=""):
            with open("log.txt", mode="w"as email_file:
                content = f"notification for {email}{message}"
                email_file.write(content)


        @app.post("/send-notification/{email}")
        async def send_notification(email: str, background_tasks: BackgroundTasks):
            background_tasks.add_task(write_notification, email, message="some notification")
            return {"message""Notification sent in the background"}

        if __name__ == "__main__":
            import uvicorn
            uvicorn.run(app, host="0.0.0.0", port=18000)

        注: 如果您需要執(zhí)行繁重的后臺(tái)計(jì)算,并且不一定需要由同一進(jìn)程運(yùn)行(例如,您不需要共享內(nèi)存、變量等),那么使用其他更大的工具(如 Celery)可能更好。

        請(qǐng)求前/后(before or after request)

        在 FastAPI 中,雖然沒(méi)有直接的 before_request 鉤子(如 Flask 中的 before_request),但你可以使用中間件(middleware)來(lái)實(shí)現(xiàn)類(lèi)似的功能。中間件允許你在每個(gè)請(qǐng)求處理之前和之后執(zhí)行代碼。

        以下是一個(gè)簡(jiǎn)單的示例,演示如何在 FastAPI 中使用中間件來(lái)實(shí)現(xiàn)類(lèi)似 before_request 的功能。

        # -*- coding: utf-8 -*-
        from fastapi import FastAPI, Request
        from starlette.middleware.base import BaseHTTPMiddleware

        app = FastAPI()


        class TraceIDMiddleware(BaseHTTPMiddleware):
            async def dispatch(self, request: Request, call_next):
                trace_id = request.headers.get('trace_id')
                if trace_id:
                    print(f"Received trace_id: {trace_id}")
                else:
                    print("No trace_id found in headers")
                response = await call_next(request)
                return response


        app.add_middleware(TraceIDMiddleware)


        @app.get("/items/")
        async def read_items():
            return {"message""Hello, World!"}


        if __name__ == "__main__":
            import uvicorn
            uvicorn.run(app, host="0.0.0.0", port=18000)

        請(qǐng)求1:

        curl http://localhost:18000/items/

        在IDE中的輸出結(jié)果為:

        No trace_id found in headers
        INFO:     127.0.0.1:51063 - "GET /items/ HTTP/1.1" 200 OK

        請(qǐng)求2:

        curl http://localhost:18000/items/ --header 'trace_id: 123'

        在IDE中的輸出結(jié)果為:

        Received trace_id: 123
        INFO:     127.0.0.1:51108 - "GET /items/ HTTP/1.1" 200 OK

        生命周期(lifespan)

        您可以定義在應(yīng)用程序 啟動(dòng) 之前應(yīng)該執(zhí)行的邏輯(代碼)。這意味著此代碼將 執(zhí)行一次,在應(yīng)用程序 開(kāi)始接收請(qǐng)求 之前。

        同樣,您也可以定義在應(yīng)用程序 關(guān)閉 時(shí)應(yīng)該執(zhí)行的邏輯(代碼)。在這種情況下,此代碼將 執(zhí)行一次,在可能處理了 許多請(qǐng)求 之后。

        因?yàn)榇舜a是在應(yīng)用程序 開(kāi)始 接收請(qǐng)求之前執(zhí)行的,并且在它 完成 處理請(qǐng)求之后立即執(zhí)行,所以它涵蓋了整個(gè)應(yīng)用程序 生命周期

        這對(duì)于設(shè)置您需要在整個(gè)應(yīng)用程序中使用的 資源 非常有用,這些資源在請(qǐng)求之間是 共享 的,或者您需要在之后 清理 它們。例如,數(shù)據(jù)庫(kù)連接池,或加載共享的機(jī)器學(xué)習(xí)模型。

        示例Python實(shí)現(xiàn)代碼:

        # -*- coding: utf-8 -*-
        from contextlib import asynccontextmanager

        from fastapi import FastAPI


        def fake_answer_to_everything_ml_model(x: float):
            return x * 42


        ml_models = {}


        @asynccontextmanager
        async def lifespan(app: FastAPI):
            # Load the ML model
            ml_models["answer_to_everything"] = fake_answer_to_everything_ml_model
            yield
            # Clean up the ML models and release the resources
            ml_models.clear()


        app = FastAPI(lifespan=lifespan)


        @app.get("/predict")
        async def predict(x: float):
            result = ml_models["answer_to_everything"](x)
            return {"result": result}


        if __name__ == "__main__":
            import uvicorn
            uvicorn.run(app, host="0.0.0.0", port=18000)

        請(qǐng)求1:

        curl http://localhost:18000/predict\?x\=2

        輸出:

        {"result":84.0}


        瀏覽 140
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 青娱乐av免费观看 | 中日韩在线视频 | 久久亚洲福利视频 | 国产精品扒开腿进入爽爽视频 | ktv夜场h肉 |