你可以使用AsyncClient()来自httpx库,如中所述这个答案, 也这个答案 and 这个答案(查看这些答案,了解有关下面演示的方法的更多详细信息)。你可以生成一个Client
在 - 的里面startup事件处理程序,将其存储在app
实例——如描述的here, 也here and here-并在每次需要时重复使用它。你可以明确地close
the Client
一旦你完成了它,使用shutdown事件处理程序.
工作示例
主服务器
当构建即将转发到其他服务器的请求时,主服务器使用request.stream()
阅读请求body
根据客户的要求,提供了async
迭代器,这样如果客户端发送了一个带有大主体的请求(例如,客户端上传了一个大文件),主服务器就不必等待整个body
在转发请求之前被接收并加载到内存中,如果您使用await request.body()
相反,如果body
无法装入 RAM。
可以用同样的方法添加多条路由/upload
下面定义了一个,指定路径以及端点的 HTTP 方法。请注意,/upload
下面的路线使用 Starlette'spath
转换以捕获任意路径,如图所示here and here。如果您愿意,您还可以指定确切的路径参数,但如果路径参数太多,下面提供了更方便的方法。无论如何,将根据下面其他服务器中的端点来评估路径,您可以在其中显式指定路径参数。
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse
from starlette.background import BackgroundTask
import httpx
app = FastAPI()
@app.on_event('startup')
async def startup_event():
client = httpx.AsyncClient(base_url='http://127.0.0.1:8001/') # this is the other server
app.state.client = client
@app.on_event('shutdown')
async def shutdown_event():
client = app.state.client
await client.aclose()
async def _reverse_proxy(request: Request):
client = request.app.state.client
url = httpx.URL(path=request.url.path, query=request.url.query.encode('utf-8'))
req = client.build_request(
request.method, url, headers=request.headers.raw, content=request.stream()
)
r = await client.send(req, stream=True)
return StreamingResponse(
r.aiter_raw(),
status_code=r.status_code,
headers=r.headers,
background=BackgroundTask(r.aclose)
)
app.add_route('/upload/{path:path}', _reverse_proxy, ['POST'])
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host='0.0.0.0', port=8000)
其他服务器
再次,为了简单起见,Request
对象用于读取正文,但您可以定义UploadFile
, Form
和其他参数如常。在下面的示例中,服务器正在侦听端口8001
.
from fastapi import FastAPI, Request
app = FastAPI()
@app.post('/upload/{p1}/{p2}')
async def upload(p1: str, p2: str, q1: str, request: Request):
return {'p1': p1, 'p2': p2, 'q1': q1, 'body': await request.body()}
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, host='0.0.0.0', port=8001)
使用以下命令测试上面的示例httpx
import httpx
url = 'http://127.0.0.1:8000/upload/hello/world'
files = {'file': open('file.txt', 'rb')}
params = {'q1': 'This is a query param'}
r = httpx.post(url, params=params, files=files)
print(r.content)