Короткий ответ
Файлы передаются через multipart/form-data, где каждая часть тела запроса имеет свои заголовки (включая Content-Disposition с именем файла); для больших файлов нужно читать и сохранять данные потоково, не загружая весь файл в память целиком, и ограничивать максимальный размер запроса явно на уровне сервера/прокси.
Как это работает подробнее
multipart/form-data разбивает тело на части с разделителем (boundary), каждая часть может быть обычным полем формы или файлом с указанным именем и типом содержимого; сервер должен распарсить это построчно/по частям, а не как единый JSON.
Пример кода
example.py
from fastapi import FastAPI, UploadFile, File, HTTPException
app = FastAPI()
MAX_SIZE = 10 * 1024 * 1024 # 10 МБ
@app.post("/uploads")
async def upload_file(file: UploadFile = File(...)):
total = 0
with open(f"/tmp/{file.filename}", "wb") as out:
while chunk := await file.read(1024 * 1024): # читаем потоково по 1 МБ
total += len(chunk)
if total > MAX_SIZE:
raise HTTPException(status_code=413, detail="File too large")
out.write(chunk)
return {"filename": file.filename, "size": total}Что использовать на практике
- Рекомендация. веб-фреймворки (FastAPI через Starlette) поддерживают потоковую обработку загружаемых файлов (
UploadFile), что позволяет сразу писать содержимое во временный файл или напрямую в объектное хранилище (S3-совместимое), не держа весь файл в оперативной памяти. Лимит на размер файла стоит задавать и на уровне приложения, и на уровне обратного прокси/балансировщика, чтобы отклонять слишком большие запросы до того, как они нагрузят процесс приложения.
Подводные камни
- Риски. читать файл целиком в память (
await file.read()для файлов произвольного размера) без ограничения, что при больших файлах или параллельных загрузках может привести к исчерпанию памяти процесса; не проверять реальный тип содержимого файла (доверять только расширению или заявленному Content-Type от клиента), что создаёт риск загрузки вредоносного содержимого под видом безопасного типа.