Middle
45
από fastapi εισαγωγή FastAPI, UploadFile, Response από fastapi.responses εισαγωγή StreamingResponse από pydantic εισαγωγή BaseModel, field_validator εισαγωγή base64 app = FastAPI() κλάση PdfSchema(BaseModel): filename: str content_type: str data: str # base64 pdf 10мб @apì.get("/data", response_model=PdfSchema) ασύγχρονη def get_data(): επιστροφή αναμονής service.get_big_data() @apì.get("/download") ασύγχρονη def download(): με ανοιχτό("big.pdf", "rb") ως f: data = f.read() επιστροφή Response(content=data, media_type="application/pdf") def heavy_pdf_parse(data: bytes) -> dict: # CPU-heavy λογική επιστρέφει {"μέγεθος": len(data)} @post("/parse") ασύγχρονη def parse(file: UploadFile): περιεχόμενο = περιμένω file.read() αποτέλεσμα = heavy_pdf_parse(περιεχόμενο) επιστροφή αποτέλεσμα @apì.get("/users") ασύγχρονη def get_users(): χρήστες = αναμονή repo.get_users() αποτέλεσμα = [] για u σε χρήστες: posts = αναμονή repo.get_posts(u["id"]) αποτέλεσμα.append({"user": u, "posts": posts}) επιστροφή αποτέλεσμα @apì.get("/download-two") ασύγχρονη def download_two(): def iterfile(): με ανοιχτό("big.pdf", "rb") ως f: yield from f επιστροφή StreamingResponse(iterfile(), media_type="application/pdf") κλάση service: @staticmethod async def get_big_data(): επιστροφή { "filename": "file.pdf", "content_type": "application/pdf", "data": base64.b64encode(b"fake").decode(), } κλάση repo: @staticmethod async def get_users(): επιστροφή [{"id": 1}, {"id": 2}] @staticmethod async def get_posts(user_id: int): επιστροφή [{"id": 1, "user id": user_id}]
Εταιρείες όπου ρωτήθηκαν
Απάντηση από AI
sobes.tech AI
В представленном коде есть несколько важных моментов, которые стоит обсудить:
-
Передача больших PDF в base64 в JSON (
PdfSchema):- Кодирует PDF в base64 и передаёт как строку. Это неэффективно для больших файлов (10 Мб и больше), так как base64 увеличивает размер примерно на 33%.
- Лучше отдавать файлы напрямую через
StreamingResponse, как в/downloadи/download-two.
-
Отдача файла через
ResponseиStreamingResponse:- В
/downloadфайл читается целиком в память, что плохо для больших файлов. - В
/download-twoиспользуется генераторiterfile(), который читает файл по частям и отдаёт потоково — это более оптимально.
- В
-
CPU-heavy функция
heavy_pdf_parse:- Если парсинг занимает много CPU, стоит рассмотреть вынесение этой логики в отдельный воркер или использовать асинхронные очереди, чтобы не блокировать event loop.
-
Асинхронные запросы в
/users:- В цикле для каждого пользователя вызывается
await repo.get_posts(u["id"]), что последовательно и может быть медленно. - Лучше запускать все запросы параллельно через
asyncio.gatherдля ускорения:
- В цикле для каждого пользователя вызывается
import asyncio
@app.get("/users")
async def get_users():
users = await repo.get_users()
async def get_user_posts(u):
posts = await repo.get_posts(u["id"])
return {"user": u, "posts": posts}
result = await asyncio.gather(*(get_user_posts(u) for u in users))
return result
- Валидация входных данных:
- В коде нет валидации входящих данных, например, для
/parseможно добавить Pydantic-модель или проверку типа файла.
- В коде нет валидации входящих данных, например, для
В целом, код демонстрирует базовые приёмы работы с FastAPI, но для продакшена стоит улучшить обработку больших файлов, параллелизм запросов и валидацию.