2

I am trying to proxy an external website (Flower monitoring URL running on different container) using python Fast API framework:

client = AsyncClient(base_url=f'http://containername:7800/monitor')

@app.get(“/monitor/{path:path}”)
async def tile_request(path: str):
    req = client.build_request("GET", path)
    r = await client.send(req, stream=True)
    return StreamingResponse(
        r.aiter_raw(),
        background=BackgroundTask(r.aclose),
        headers=r.headers
   )

It is able to proxy the container URL for every path. For ex.

http://python_server:8001/monitor/dashboard --> http://containername:7800/monitor/dashboard

http://python_server:8001/monitor/tasks --> http://containername:7800/monitor/tasks

It works well. But it fails when the PATH has some query params in the URL.

For ex.

http://python_server:8001/monitor/dashboard?json=1&_=1641485992460 --> redirects to http://containername:7800/monitor/dashboard 

(Please note that no query params are appended to the URL).

Can anyone please help with how we can proxy this external website's any path with any query param.

undefined
  • 3,464
  • 11
  • 48
  • 90
  • you only pass the path, you dont capture or pass the query params. you can get them from the request object, – Chris Doyle Jan 06 '22 at 16:33
  • Does this answer your question? [FastAPI variable query parameters](https://stackoverflow.com/questions/62279710/fastapi-variable-query-parameters) – Chris Doyle Jan 06 '22 at 16:33
  • Thanks, I think it should work.. need to check how i can pass the query param to httpx client. – undefined Jan 06 '22 at 16:36
  • Please have a look at related answers [here](https://stackoverflow.com/a/73736138/17865804), as well as [here](https://stackoverflow.com/a/73770074/17865804) and [here](https://stackoverflow.com/a/73672334/17865804) – Chris Jun 18 '23 at 13:58

1 Answers1

4

This code works for me and is used in production:

import httpx
from httpx import AsyncClient
from fastapi import Request
from fastapi.responses import StreamingResponse
from starlette.background import BackgroundTask

app = FastAPI()
HTTP_SERVER = AsyncClient(base_url="http://localhost:8000/")

async def _reverse_proxy(request: Request):
    url = httpx.URL(path=request.url.path, query=request.url.query.encode("utf-8"))
    rp_req = HTTP_SERVER.build_request(
        request.method, url, headers=request.headers.raw, content=await request.body()
    )
    rp_resp = await HTTP_SERVER.send(rp_req, stream=True)
    return StreamingResponse(
        rp_resp.aiter_raw(),
        status_code=rp_resp.status_code,
        headers=rp_resp.headers,
        background=BackgroundTask(rp_resp.aclose),
    )

app.add_route("/{path:path}", _reverse_proxy, ["GET", "POST"])
niteris
  • 61
  • 1
  • 3