Įvaldykite FastAPI tarpinę programinę įrangą: pasirinktinės funkcijos, autentifikavimas, registravimas, klaidų valdymas ir geriausia praktika patikimoms API.
Python FastAPI tarpinė programinė įranga: išsamus vadovas, skirtas užklausų ir atsakymų apdorojimui
Šiuolaikinio žiniatinklio kūrimo pasaulyje našumas, saugumas ir palaikomumas yra itin svarbūs. „Python“ „FastAPI“ karkasas sparčiai išpopuliarėjo dėl neįtikėtino greičio ir kūrėjams patogių funkcijų. Viena iš jo galingiausių, tačiau kartais klaidingai suprantamų funkcijų yra tarpinė programinė įranga. Tarpinė programinė įranga veikia kaip esminė grandis užklausų ir atsakymų apdorojimo grandinėje, leidžianti kūrėjams vykdyti kodą, modifikuoti duomenis ir įgyvendinti taisykles prieš užklausai pasiekiant tikslą arba prieš atsakymui išsiunčiant atgal klientui.
Šis išsamus vadovas skirtas pasaulinei kūrėjų auditorijai, nuo tų, kurie tik pradeda dirbti su „FastAPI“, iki patyrusių specialistų, norinčių pagilinti savo žinias. Mes nagrinėsime pagrindines tarpinės programinės įrangos sąvokas, parodysime, kaip kurti individualius sprendimus, ir apžvelgsime praktinius, realaus pasaulio naudojimo atvejus. Galiausiai būsite pasirengę pasitelkti tarpinę programinę įrangą, kad sukurtumėte patikimesnes, saugesnes ir efektyvesnes API.
Kas yra tarpinė programinė įranga žiniatinklio karkasų kontekste?
Prieš pradedant gilintis į kodą, svarbu suprasti šią sąvoką. Įsivaizduokite savo programos užklausos-atsakymo ciklą kaip vamzdyną ar surinkimo liniją. Kai klientas siunčia užklausą jūsų API, ji ne iš karto pasiekia jūsų galinio punkto logiką. Vietoj to, ji keliauja per apdorojimo veiksmų seką. Panašiai, kai jūsų galinis punktas generuoja atsakymą, jis keliauja atgal per šiuos veiksmus, prieš pasiekdamas klientą. Tarpinės programinės įrangos komponentai yra būtent šie žingsniai vamzdyne.
Populiari analogija yra svogūno modelis. Svogūno branduolys yra jūsų programos verslo logika (galinis punktas). Kiekvienas svogūno sluoksnis, supantis branduolį, yra tarpinės programinės įrangos dalis. Užklausa turi nusilupti per kiekvieną išorinį sluoksnį, kad pasiektų branduolį, o atsakymas keliauja atgal per tuos pačius sluoksnius. Kiekvienas sluoksnis gali patikrinti ir modifikuoti užklausą jai ateinant ir atsakymą jai išeinant.
Iš esmės, tarpinė programinė įranga yra funkcija arba klasė, turinti prieigą prie užklausos objekto, atsakymo objekto ir kitos tarpinės programinės įrangos programos užklausos-atsakymo cikle. Jos pagrindiniai tikslai apima:
- Kodo vykdymas: Atlieka veiksmus kiekvienai gaunamai užklausai, pvz., registravimą ar našumo stebėjimą.
- Užklausos ir atsakymo modifikavimas: Pridėti antraštes, suspausti atsakymo turinį arba transformuoti duomenų formatus.
- Ciklo nutraukimas: Ankstyvas užklausos-atsakymo ciklo nutraukimas. Pavyzdžiui, autentifikavimo tarpinė programinė įranga gali blokuoti neautentifikuotą užklausą, kol ji dar nepasiekė numatyto galinio punkto.
- Pasaulinių problemų valdymas: Tvarkyti plataus masto problemas, tokias kaip klaidų valdymas, CORS („Cross-Origin Resource Sharing“) ir sesijų valdymas centralizuotoje vietoje.
„FastAPI“ yra sukurta remiantis „Starlette“ įrankių rinkiniu, kuris užtikrina patikimą ASGI („Asynchronous Server Gateway Interface“) standarto įgyvendinimą. Tarpinė programinė įranga yra esminė ASGI sąvoka, todėl ji yra pilnateisė „FastAPI“ ekosistemos dalis.
Paprasčiausia forma: FastAPI tarpinė programinė įranga su dekoratoriumi
„FastAPI“ suteikia paprastą būdą pridėti tarpinę programinę įrangą naudojant @app.middleware("http") dekoratorių. Tai puikiai tinka paprastai, savarankiškai logikai, kuri turi veikti kiekvienai HTTP užklausai.
Sukurkime klasikinį pavyzdį: tarpinę programinę įrangą, skirtą apskaičiuoti kiekvienos užklausos apdorojimo laiką ir pridėti jį prie atsakymo antraščių. Tai nepaprastai naudinga našumo stebėjimui.
Pavyzdys: Apdorojimo laiko tarpinė programinė įranga
Pirmiausia, įsitikinkite, kad turite įdiegtą „FastAPI“ ir ASGI serverį, pvz., „Uvicorn“:
pip install fastapi uvicorn
Dabar parašykime kodą faile pavadinimu main.py:
import time
from fastapi import FastAPI, Request
app = FastAPI()
# Define the middleware function
@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
# Record the start time when the request comes in
start_time = time.time()
# Proceed to the next middleware or the endpoint
response = await call_next(request)
# Calculate the processing time
process_time = time.time() - start_time
# Add the custom header to the response
response.headers["X-Process-Time"] = str(process_time)
return response
@app.get("/")
async def root():
# Simulate some work
time.sleep(0.5)
return {"message": "Hello, World!"}
Norėdami paleisti šią programą, naudokite komandą:
uvicorn main:app --reload
Dabar, jei išsiųsite užklausą į http://127.0.0.1:8000 naudodami įrankį, pvz., cURL, arba API klientą, pvz., „Postman“, atsakyme pamatysite naują antraštę X-Process-Time, kurios vertė bus maždaug 0,5 sekundės.
Kodo dekonstravimas:
@app.middleware("http"): Šis dekoratorius registruoja mūsų funkciją kaip HTTP tarpinės programinės įrangos dalį.async def add_process_time_header(request: Request, call_next):: Tarpinės programinės įrangos funkcija turi būti asinchroninė. Ji gauna gaunamąRequestobjektą ir specialią funkcijącall_next.response = await call_next(request): Tai yra pati svarbiausia eilutė.call_nextperduoda užklausą kitam vamzdyno žingsniui (arba kitai tarpinei programinei įrangai, arba tikrajai kelio operacijai). Jūs privalote `await` šį iškvietimą. Rezultatas yraResponseobjektas, sugeneruotas galinio punkto.response.headers[...] = ...: Gavus atsakymą iš galinio punkto, galime jį modifikuoti, šiuo atveju, pridėdami pasirinktinę antraštę.return response: Galiausiai, modifikuotas atsakymas grąžinamas, kad būtų išsiųstas klientui.
Savo pasirinktinės tarpinės programinės įrangos kūrimas su klasėmis
Nors dekoratorių metodas yra paprastas, jis gali tapti ribotu sudėtingesniems scenarijams, ypač kai jūsų tarpinė programinė įranga reikalauja konfigūracijos arba turi valdyti tam tikrą vidinę būseną. Tokiais atvejais „FastAPI“ (per „Starlette“) palaiko klasėmis pagrįstą tarpinę programinę įrangą, naudojant BaseHTTPMiddleware.
Klasėmis pagrįstas metodas suteikia geresnę struktūrą, leidžia įpurkšti priklausomybes į jo konstruktorių ir paprastai yra lengviau prižiūrimas sudėtingai logikai. Pagrindinė logika yra asinchroniniame dispatch metode.
Pavyzdys: Klasėmis pagrįsta API rakto autentifikavimo tarpinė programinė įranga
Sukurkime praktiškesnę tarpinę programinę įrangą, kuri apsaugos mūsų API. Ji patikrins konkrečią antraštę X-API-Key, ir jei raktas nėra pateiktas arba neteisingas, ji nedelsiant grąžins 403 Forbidden klaidos atsakymą. Tai yra užklausos „trumpinimo“ pavyzdys.
Faile main.py:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.responses import Response
# A list of valid API keys. In a real application, this would come from a database or a secure vault.
VALID_API_KEYS = ["my-super-secret-key", "another-valid-key"]
class APIKeyMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
api_key = request.headers.get("X-API-Key")
if api_key not in VALID_API_KEYS:
# Short-circuit the request and return an error response
return JSONResponse(
status_code=403,
content={"detail": "Forbidden: Invalid or missing API Key"}
)
# If the key is valid, proceed with the request
response = await call_next(request)
return response
app = FastAPI()
# Add the middleware to the application
app.add_middleware(APIKeyMiddleware)
@app.get("/")
async def root():
return {"message": "Welcome to the secure zone!"}
Dabar, kai paleisite šią programą:
- Užklausa be
X-API-Keyantraštės (arba su neteisinga reikšme) gaus 403 būsenos kodą ir JSON klaidos pranešimą. - Užklausa su antrašte
X-API-Key: my-super-secret-keybus sėkminga ir gaus 200 OK atsakymą.
Šis modelis yra nepaprastai galingas. Galinio punkto kodas / neturi žinoti nieko apie API rakto patvirtinimą; šis rūpestis yra visiškai atskirtas į tarpinės programinės įrangos sluoksnį.
Dažni ir galingi tarpinės programinės įrangos naudojimo atvejai
Tarpinė programinė įranga yra puikus įrankis valdyti plataus masto problemas. Panagrinėkime keletą dažniausių ir įtakingiausių naudojimo atvejų.
1. Centralizuotas registravimas
Išsamus registravimas yra būtinas gamybos programoms. Tarpinė programinė įranga leidžia sukurti vieną tašką, kuriame registruojate svarbią informaciją apie kiekvieną užklausą ir jos atitinkamą atsakymą.
Pavyzdys: Registravimo tarpinė programinė įranga:
import logging
from fastapi import FastAPI, Request
import time
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def logging_middleware(request: Request, call_next):
start_time = time.time()
# Log request details
logger.info(f"Incoming request: {request.method} {request.url.path}")
response = await call_next(request)
process_time = time.time() - start_time
# Log response details
logger.info(f"Response status: {response.status_code} | Process time: {process_time:.4f}s")
return response
Ši tarpinė programinė įranga registruoja užklausos metodą ir kelią jai ateinant, o atsakymo būsenos kodą ir bendrą apdorojimo laiką jai išeinant. Tai suteikia neįkainojamą matomumą jūsų programos srautui.
2. Pasaulinis klaidų valdymas
Pagal numatytuosius nustatymus, nevaldoma išimtis jūsų kode sukels 500 vidinio serverio klaidą, potencialiai atskleidžiančią kamino pėdsakus ir įgyvendinimo detales klientui. Pasaulinė klaidų valdymo tarpinė programinė įranga gali pagauti visas išimtis, užregistruoti jas vidinei peržiūrai ir grąžinti standartizuotą, vartotojui patogų klaidos atsakymą.
Pavyzdys: Klaidų valdymo tarpinė programinė įranga:
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
import logging
logger = logging.getLogger(__name__)
app = FastAPI()
@app.middleware("http")
async def error_handling_middleware(request: Request, call_next):
try:
return await call_next(request)
except Exception as e:
logger.error(f"An unhandled error occurred: {e}", exc_info=True)
return JSONResponse(
status_code=500,
content={"detail": "An internal server error occurred. Please try again later."}
)
@app.get("/error")
async def cause_error():
return 1 / 0 # This will raise a ZeroDivisionError
Su šia tarpine programine įranga užklausa į /error nebesugriaus serverio ir neatskleis kamino pėdsakų. Vietoj to, ji elegantiškai grąžins 500 būsenos kodą su švariu JSON turiniu, o visa klaida bus užregistruota serverio pusėje, kad kūrėjai galėtų ją ištirti.
3. CORS (Cross-Origin Resource Sharing)
Jei jūsų priekinė programa aptarnaujama iš kitokio domeno, protokolo ar prievado nei jūsų „FastAPI“ galinė sistema, naršyklės blokuos užklausas dėl tos pačios kilmės politikos (Same-Origin Policy). CORS yra mechanizmas, skirtas sušvelninti šią politiką. „FastAPI“ suteikia specialią, labai konfigūruojamą `CORSMiddleware` šiam tikslui.
Pavyzdys: CORS konfigūracija:
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
# Define the list of allowed origins. Use "*" for public APIs, but be specific for better security.
origins = [
"http://localhost:3000",
"https://my-production-frontend.com",
]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True, # Allow cookies to be included in cross-origin requests
allow_methods=["*"], # Allow all standard HTTP methods
allow_headers=["*"], # Allow all headers
)
Tai yra viena iš pirmųjų tarpinės programinės įrangos dalių, kurią greičiausiai pridėsite prie bet kurio projekto su atskirtu priekiniu galu, todėl lengva valdyti skirtingos kilmės politiką iš vienos, centralizuotos vietos.
4. GZip suspaudimas
HTTP atsakymų suspaudimas gali žymiai sumažinti jų dydį, todėl klientams atsakymai įkeliami greičiau ir sumažėja pralaidumo sąnaudos. „FastAPI“ apima `GZipMiddleware`, kad tai būtų tvarkoma automatiškai.
Pavyzdys: GZip tarpinė programinė įranga:
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
app = FastAPI()
# Add the GZip middleware. You can set a minimum size for compression.
app.add_middleware(GZipMiddleware, minimum_size=1000)
@app.get("/")
async def root():
# This response is small and will not be gzipped.
return {"message": "Hello World"}
@app.get("/large-data")
async def large_data():
# This large response will be automatically gzipped by the middleware.
return {"data": "a_very_long_string..." * 1000}
Su šia tarpine programine įranga, bet koks atsakymas, didesnis nei 1000 baitų, bus suspaustas, jei klientas nurodo, kad priima GZip kodavimą (ką daro beveik visos šiuolaikinės naršyklės ir klientai).
Pažangios sąvokos ir geriausia praktika
Kai įgysite daugiau įgūdžių su tarpine programine įranga, svarbu suprasti kai kuriuos niuansus ir geriausią praktiką, kad parašytumėte švarų, efektyvų ir nuspėjamą kodą.
1. Tarpinės programinės įrangos eilės tvarka yra svarbi!
Tai yra svarbiausia taisyklė, kurią reikia prisiminti. Tarpinė programinė įranga apdorojama tokia tvarka, kokia ji pridedama prie programos. Pirmoji pridėta tarpinė programinė įranga yra išorinis „svogūno“ sluoksnis.
Apsvarstykite šį nustatymą:
app.add_middleware(ErrorHandlingMiddleware) # Išorinis
app.add_middleware(LoggingMiddleware)
app.add_middleware(AuthenticationMiddleware) # Vidinis
Užklausos srautas būtų toks:
ErrorHandlingMiddlewaregauna užklausą. Ji apgaubia savo `call_next` `try...except` bloku.- Ji iškviečia `next`, perduodant užklausą
LoggingMiddleware. LoggingMiddlewaregauna užklausą, registruoja ją ir iškviečia `next`.AuthenticationMiddlewaregauna užklausą, patvirtina kredencialus ir iškviečia `next`.- Užklausa galiausiai pasiekia galinį punktą.
- Galinio punkto funkcija grąžina atsakymą.
AuthenticationMiddlewaregauna atsakymą ir perduoda jį aukštyn.LoggingMiddlewaregauna atsakymą, registruoja jį ir perduoda jį aukštyn.ErrorHandlingMiddlewaregauna galutinį atsakymą ir grąžina jį klientui.
Ši tvarka yra logiška: klaidų tvarkyklė yra išorėje, kad galėtų aptikti klaidas iš bet kurio tolesnio sluoksnio, įskaitant kitą tarpinę programinę įrangą. Autentifikavimo sluoksnis yra giliai viduje, todėl mes nesivarginame registruoti ar apdoroti užklausų, kurios vis tiek bus atmestos.
2. Duomenų perdavimas naudojant `request.state`
Kartais tarpinei programinei įrangai reikia perduoti informaciją galiniam punktui. Pavyzdžiui, autentifikavimo tarpinė programinė įranga gali iškoduoti JWT ir išgauti vartotojo ID. Kaip ji gali padaryti šį vartotojo ID prieinamą kelio operacijos funkcijai?
Neteisingas būdas yra tiesiogiai modifikuoti užklausos objektą. Teisingas būdas yra naudoti request.state objektą. Tai paprastas, tuščias objektas, skirtas būtent šiam tikslui.
Pavyzdys: Vartotojo duomenų perdavimas iš tarpinės programinės įrangos
# Jūsų autentifikavimo tarpinės programinės įrangos „dispatch“ metode:
# ... po žetono patvirtinimo ir vartotojo dekodavimo ...
user_data = {"id": 123, "username": "global_dev"}
request.state.user = user_data
response = await call_next(request)
# Jūsų galiniame punkte:
@app.get("/profile")
async def get_user_profile(request: Request):
current_user = request.state.user
return {"profile_for": current_user}
Tai padeda išlaikyti švarią logiką ir neapkrauna `Request` objekto vardo erdvės.
3. Našumo aspektai
Nors tarpinė programinė įranga yra galinga, kiekvienas sluoksnis prideda šiek tiek papildomo krūvio. Didelio našumo programoms atminkite šiuos dalykus:
- Išlaikykite ją efektyvią: Tarpinės programinės įrangos logika turėtų būti kuo greitesnė ir efektyvesnė.
- Būkite asinchroniniai: Jei jūsų tarpinei programinei įrangai reikia atlikti įvesties/išvesties operacijas (pvz., duomenų bazės patikrinimą), užtikrinkite, kad ji būtų visiškai `async`, kad neužblokuotų serverio įvykių ciklo.
- Naudokite tikslingai: Nedėkite tarpinės programinės įrangos, kurios jums nereikia. Kiekviena iš jų padidina iškvietimų steko gylį ir apdorojimo laiką.
4. Tarpinės programinės įrangos testavimas
Tarpinė programinė įranga yra kritinė jūsų programos logikos dalis ir turi būti nuodugniai patikrinta. „FastAPI“ `TestClient` tai supaprastina. Galite rašyti testus, kurie siunčia užklausas su reikiamomis ir nereikalingomis sąlygomis (pvz., su galiojančiu API raktu ir be jo) ir patvirtinti, kad tarpinė programinė įranga veikia taip, kaip tikimasi.
Pavyzdys: APIKeyMiddleware testas:
from fastapi.testclient import TestClient
from .main import app # Importuokite savo FastAPI programą
client = TestClient(app)
def test_request_without_api_key_is_forbidden():
response = client.get("/")
assert response.status_code == 403
assert response.json() == {"detail": "Forbidden: Invalid or missing API Key"}
def test_request_with_valid_api_key_is_successful():
headers = {"X-API-Key": "my-super-secret-key"}
response = client.get("/", headers=headers)
assert response.status_code == 200
assert response.json() == {"message": "Welcome to the secure zone!"}
Išvada
„FastAPI“ tarpinė programinė įranga yra esminė ir galinga priemonė bet kuriam kūrėjui, kuriančiam modernias žiniatinklio API. Ji suteikia elegantišką ir pakartotinai naudojamą būdą spręsti plataus masto problemas, atskiriant jas nuo jūsų pagrindinės verslo logikos. Perimant ir apdorojant kiekvieną užklausą ir atsakymą, tarpinė programinė įranga leidžia įdiegti patikimą registravimą, centralizuotą klaidų valdymą, griežtas saugumo politikas ir našumo patobulinimus, tokius kaip suspaudimas.
Nuo paprasto @app.middleware("http") dekoratoriaus iki sudėtingų, klasėmis pagrįstų sprendimų, turite lankstumą pasirinkti tinkamą metodą savo poreikiams. Suprasdami pagrindines sąvokas, dažnus naudojimo atvejus ir geriausią praktiką, pvz., tarpinės programinės įrangos eiliškumą ir būsenos valdymą, galite kurti švaresnes, saugesnes ir lengviau prižiūrimas „FastAPI“ programas.
Dabar jūsų eilė. Pradėkite integruoti pasirinktinę tarpinę programinę įrangą į savo kitą „FastAPI“ projektą ir atraskite naują valdymo ir elegancijos lygį savo API dizaine. Galimybės yra plačios, o įvaldžius šią funkciją neabejotinai tapsite efektyvesniu ir našesniu kūrėju.