Multipart-uppladdningar och innehållsvalidering
Ta emot UploadFile-indata, validera MIME-typer och storleksgränser samt skydda mot skadliga payloads.
Multipart-uppladdningar och innehållsvalidering är en gratis lektion i Bootcamp i backendutveckling med FastAPI på CoddyKit. Detta är lektion 1 av 4. Du kan läsa vilka 3 lektioner som helst i den här lärvägen kostnadsfritt i sin helhet – därefter låser CoddyKit PRO upp alla lektioner, plus praktisk övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Den ingår i lärvägen för Bootcamp i backendutveckling med FastAPI, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Bootcamp i backendutveckling med FastAPI innehåller totalt 4 lektioner.
Varför multipart-uppladdningar är viktiga
Vanliga JSON-begärandekroppar kan inte effektivt bära råa binärfiler. När en bild, PDF eller video ska laddas upp skickar webbläsare en begäran av typen multipart/form-data, som packar varje fält (textvärden och filbyte) i separata delar med egna headers.
FastAPI exponerar inkommande filer genom två hjälpmedel:
- UploadFile — ett spoolat filobjekt som automatiskt håller små filer i minnet och stora filer på disk.
- File() — en parameterindikator som talar om för FastAPI att läsa värdet från multipart-kroppen.
I den här lektionen tar du emot uppladdningar, validerar deras MIME-typ och storlek och avvisar skadliga eller för stora nyttolaster innan de når lagringen.
Din första UploadFile-endpoint
En parameter av typen UploadFile ger dig det ursprungliga filename, den angivna content_type och asynkrona metoder som read() och seek(). Deklarera den alltid med = File(...) så att FastAPI tolkar den från multipart-kroppen.
Observera att hanteraren är async eftersom fil-I/O på UploadFile kan invänta resultat.
from fastapi import FastAPI, UploadFile, File
app = FastAPI()
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
contents = await file.read()
return {
"filename": file.filename,
"content_type": file.content_type,
"size_bytes": len(contents),
}Lita aldrig på den angivna content_type
content_type på en UploadFile kommer direkt från klienten. En angripare kan märka en .exe som image/png. Använd detta som ett snabbt första filter, men aldrig som den enda kontrollen.
En robust pipeline gör tre saker, i denna ordning:
- Avvisa uppenbart felaktiga angivna typer snabbt (billigt).
- Upprätthåll en hård storleksgräns medan filen strömmas (förhindrar att minnet tar slut).
- Inspektera de faktiska filbytena (magiska tal) för att bekräfta den verkliga typen.
Följande scener bygger upp varje lager.
Tillåtna MIME-typer
Använd alltid en tillåtelselista, aldrig en blockeringslista. Ange exakt de typer du stöder och avvisa allt annat. Returnera 415 Unsupported Media Type när den angivna typen inte är tillåten.
Håll mängden liten och uttrycklig så att nya filformat blir ett medvetet beslut, inte en olyckshändelse.
from fastapi import FastAPI, UploadFile, File, HTTPException
app = FastAPI()
ALLOWED_TYPES = {"image/jpeg", "image/png", "application/pdf"}
@app.post("/documents")
async def create_document(file: UploadFile = File(...)):
if file.content_type not in ALLOWED_TYPES:
raise HTTPException(
status_code=415,
detail=f"Unsupported type: {file.content_type}",
)
return {"ok": True, "filename": file.filename}Upprätthålla en storleksgräns genom strömning
Om du anropar await file.read() läses hela filen in i minnet. En uppladdning på 2 GB kan få din worker att krascha. Läs i stället fasta block och avbryt så snart den löpande totalsumman överskrider gränsen.
Returnera 413 Request Entity Too Large när gränsen överskrids. Då hålls minnesanvändningen begränsad oavsett hur stor fil klienten påstår att den är.
from fastapi import FastAPI, UploadFile, File, HTTPException
app = FastAPI()
MAX_SIZE = 5 * 1024 * 1024 # 5 MB
CHUNK = 1024 * 1024 # 1 MB
@app.post("/upload")
async def upload(file: UploadFile = File(...)):
total = 0
while chunk := await file.read(CHUNK):
total += len(chunk)
if total > MAX_SIZE:
raise HTTPException(413, "File too large")
return {"filename": file.filename, "size": total}Strömma direkt till disk på ett säkert sätt
När storlek och typ har godkänts strömmar du blocken till en destinationsfil i stället för att hålla dem i minnet. Kombinera storlekskontrollen med skrivloopen så att du avbryter tidigt vid för stora nyttolaster och aldrig sparar en delvis uppladdad men enorm fil.
Använd await file.seek(0) om du läste strömmen tidigare och behöver börja om.
import aiofiles
from fastapi import UploadFile, File, HTTPException
MAX_SIZE = 5 * 1024 * 1024
async def save_upload(file: UploadFile, dest: str) -> int:
total = 0
async with aiofiles.open(dest, "wb") as out:
while chunk := await file.read(1024 * 1024):
total += len(chunk)
if total > MAX_SIZE:
raise HTTPException(413, "File too large")
await out.write(chunk)
return totalVerifiera det verkliga innehållet med magiska tal
Den mest tillförlitliga typkontrollen inspekterar filens inledande byte, dess magiska tal. En PNG börjar alltid med \x89PNG\r\n\x1a\n, en JPEG med \xff\xd8\xff och en PDF med %PDF.
Denna rena Python-funktion mappar ett byteprefix till en verklig MIME-typ. Du kan köra den i en onlinebedömare helt utan ramverk.
def sniff_mime(head: bytes) -> str | None:
signatures = {
b"\x89PNG\r\n\x1a\n": "image/png",
b"\xff\xd8\xff": "image/jpeg",
b"%PDF": "application/pdf",
}
for magic, mime in signatures.items():
if head.startswith(magic):
return mime
return None
if __name__ == "__main__":
print(sniff_mime(b"\x89PNG\r\n\x1a\nrest")) # image/png
print(sniff_mime(b"%PDF-1.7")) # application/pdf
print(sniff_mime(b"MZ\x90\x00")) # None (rejected)Korskontrollera angiven och verklig typ
Kombinera lagren: läs precis tillräckligt många byte för att identifiera det magiska talet, bekräfta att det finns i din tillåtelselista och kontrollera att det stämmer med det klienten angav. En avvikelse (angiven image/png men de verkliga bytena visar PDF) är en stark signal om en skadlig eller felaktig klient, så avvisa den.
Anropa await file.seek(0) efter identifieringen så att hela filen fortfarande kan sparas.
from fastapi import UploadFile, File, HTTPException
ALLOWED = {"image/png", "image/jpeg", "application/pdf"}
async def validate_type(file: UploadFile) -> str:
head = await file.read(8)
await file.seek(0)
real = sniff_mime(head)
if real not in ALLOWED:
raise HTTPException(415, "Content not allowed")
if file.content_type != real:
raise HTTPException(415, "Declared type mismatch")
return realSanera filnamn
Använd aldrig filnamnet från klienten direkt som lagringssökväg. Namn som ../../etc/passwd möjliggör sökvägstraversering, och ovanliga tecken kan få filsystem att fungera fel. Ta bort katalognamnet, behåll en säker teckenuppsättning och föredra ett genererat namn tillsammans med ett validerat filnamnstillägg.
Denna hjälpfunktion är ren Python och kan köras i en onlinebedömare.
import re
import uuid
from pathlib import PurePosixPath
EXT_FOR = {"image/png": ".png", "image/jpeg": ".jpg", "application/pdf": ".pdf"}
def safe_name(original: str, mime: str) -> str:
base = PurePosixPath(original).name # drop any path parts
base = re.sub(r"[^A-Za-z0-9._-]", "_", base) # keep safe chars
ext = EXT_FOR.get(mime, "")
return f"{uuid.uuid4().hex}{ext}"
if __name__ == "__main__":
print(safe_name("../../etc/passwd", "image/png").endswith(".png"))
print("/" not in safe_name("weird name!.jpg", "image/jpeg"))Hantera flera filer samtidigt
Om du vill ta emot flera filer i samma begäran deklarerar du parametern som en list[UploadFile]. Klienten skickar samma formulärfältnamn flera gånger. Validera varje fil separat och misslyckas med hela begäran om någon fil är ogiltig, så att ofullständiga uppladdningar aldrig lämnar ett inkonsekvent tillstånd.
from fastapi import FastAPI, UploadFile, File, HTTPException
app = FastAPI()
ALLOWED = {"image/png", "image/jpeg"}
@app.post("/gallery")
async def gallery(files: list[UploadFile] = File(...)):
if len(files) > 10:
raise HTTPException(400, "Too many files (max 10)")
for f in files:
if f.content_type not in ALLOWED:
raise HTTPException(415, f"{f.filename}: bad type")
return {"received": [f.filename for f in files]}Paketering av validering som ett beroende
Att upprepa typ- och storlekskontroller i varje endpoint är felbenäget. Kapsla in dem i ett återanvändbart FastAPI-beroende. Beroendet kör hela pipelinen och returnerar en ren, validerad UploadFile, så att din route kan fokusera på affärslogik.
Detta är formen för produktion: tillåtelselista, strömmad storleksgräns, identifiering med magiskt tal och säkra filnamn på samma ställe.
from fastapi import Depends, UploadFile, File, HTTPException
MAX_SIZE = 5 * 1024 * 1024
async def validated_upload(file: UploadFile = File(...)) -> UploadFile:
head = await file.read(8)
if sniff_mime(head) not in {"image/png", "image/jpeg", "application/pdf"}:
raise HTTPException(415, "Unsupported content")
total = len(head)
while chunk := await file.read(1024 * 1024):
total += len(chunk)
if total > MAX_SIZE:
raise HTTPException(413, "File too large")
await file.seek(0)
return file
@app.post("/secure-upload")
async def secure_upload(file: UploadFile = Depends(validated_upload)):
return {"filename": file.filename}Snabbkontroll: välja rätt skydd
En endpoint tar emot profilbilder. En användare laddar upp en fil på 3 GB vars content_type-header anger image/png, men vars byte egentligen är en körbar fil. Vilken enda kombination av kontroller skyddar servern på ett tillförlitligt sätt?
Sammanfattning: ett uppladdningsförsvar i flera lager
Du har byggt en komplett och defensiv uppladdningspipeline för FastAPI:
- UploadFile + File() tar emot multipart-data med I/O som lämpar sig för strömning.
- Lägg den angivna MIME-typen i en tillåtelselista och returnera
415för allt oväntat, men lita aldrig enbart på headern. - Strömma i block och avbryt med
413när en storleksgräns överskrids, så att minnesanvändningen hålls begränsad. - Identifiera magiska tal för att bekräfta den verkliga innehållstypen och avvisa avvikelser mellan angiven och verklig typ.
- Sanera filnamn och använd genererade namn för att stoppa sökvägstraversering.
- Paketeringen som ett beroende gör att varje endpoint kan återanvända samma skydd.
Kontroller i flera lager, ordnade från billiga till dyra, ger ett robust skydd mot för stora och skadliga uppladdningar.
Lär dig Bootcamp i backendutveckling med FastAPI med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 21
- Lektioner
- 84
Vanliga frågor
Är lektionen ”Multipart-uppladdningar och innehållsvalidering” gratis?
Ja – du kan läsa vilka 3 lektioner som helst i lärvägen Bootcamp i backendutveckling med FastAPI, inklusive ”Multipart-uppladdningar och innehållsvalidering”, kostnadsfritt i sin helhet här på webben. Därefter låser CoddyKit PRO upp alla lektioner, plus interaktiv övning med en inbyggd kodredigerare och en AI-lärare dygnet runt. Kursen i Bootcamp i backendutveckling med FastAPI innehåller totalt 4 lektioner.
Vad lär jag mig i ”Multipart-uppladdningar och innehållsvalidering”?
Ta emot UploadFile-indata, validera MIME-typer och storleksgränser samt skydda mot skadliga payloads. Ni övar på Bootcamp i backendutveckling med FastAPI med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Bootcamp i backendutveckling med FastAPI?
Du behöver inga förkunskaper. Utbildningen i Bootcamp i backendutveckling med FastAPI på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.
Hur lång tid tar lektionen ”Multipart-uppladdningar och innehållsvalidering”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Bootcamp i backendutveckling med FastAPI-lektionen?
Ja. Varje Bootcamp i backendutveckling med FastAPI-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Multipart-uppladdningar och innehållsvalidering
- Strömmande svar och range requests
- Avlasta lagring till S3-kompatibla buckets
- Asynkron bild- och dokumenttransformering