这个答案的代码和信息来自以下答案。因此,请查看它们以获取更多详细信息和解释:
- 如何在每个FastAPI端点中初始化全局对象或变量并重复使用它?
- 在Uvicorn/FastAPI中进行下游Https请求的正确方法是什么?
- 在FastAPI端点中使用concurrent.futures.ThreadPoolExecutor调用是否危险?
- FastAPI python:如何在后台运行线程?
- 在FastAPI中从在线视频URL返回文件/流响应
- FastAPI UploadFile与Flask相比较慢
- 如何使用FastAPI下载大文件?
- 如何在同一运行事件循环中运行另一个应用程序?
以下提供的解决方案使用了
httpx
库,该库为Python提供了一个强大的HTTP客户端库,具有
async
API,并支持HTTP/1.1和HTTP/2。在
asyncio
应用程序中,还使用了
aiofiles
库来处理文件操作(如将文件写入磁盘)。用于测试解决方案的公共视频(大文件)可以在
这里找到。
解决方案1
如果您希望在整个应用程序中重用HTTP客户端,请使用此解决方案。
from fastapi import FastAPI, Request
from contextlib import asynccontextmanager
from fastapi.responses import StreamingResponse
from starlette.background import BackgroundTask
import asyncio
import aiofiles
import httpx
async def download_large_file(client: httpx.AsyncClient):
large_file_url = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
path = 'save_to/video.mp4'
req = client.build_request('GET', large_file_url)
r = await client.send(req, stream=True)
async with aiofiles.open(path, 'wb') as f:
async for chunk in r.aiter_raw():
await f.write(chunk)
await r.aclose()
@asynccontextmanager
async def lifespan(app: FastAPI):
async with httpx.AsyncClient() as client:
asyncio.create_task(download_large_file(client))
yield {'client': client}
app = FastAPI(lifespan=lifespan)
@app.get('/')
async def home():
return 'Hello World!'
@app.get('/download')
async def download_some_file(request: Request):
client = request.state.client
req = client.build_request('GET', 'https://www.example.com')
r = await client.send(req, stream=True)
return StreamingResponse(r.aiter_raw(), background=BackgroundTask(r.aclose))
解决方案2
如果您不需要重复使用HTTP客户端,只需要在启动时使用它,请使用此解决方案。
from fastapi import FastAPI
from contextlib import asynccontextmanager
import asyncio
import aiofiles
import httpx
async def download_large_file():
large_file_url = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4'
path = 'save_to/video.mp4'
async with httpx.AsyncClient() as client:
async with client.stream('GET', large_file_url) as r:
async with aiofiles.open(path, 'wb') as f:
async for chunk in r.aiter_raw():
await f.write(chunk)
@asynccontextmanager
async def lifespan(app: FastAPI):
asyncio.create_task(download_large_file())
yield
app = FastAPI(lifespan=lifespan)
@app.get('/')
async def home():
return 'Hello World!'
threading
或asyncio
来异步执行下载任务。 - undefined