最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

python - How do I make FastAPI URLs include the proxied URL? - Stack Overflow

programmeradmin0浏览0评论

I have a FastAPI application that is behind a NextJS reverse proxy. I'm using NextJS rewrites, which sets the x-forwarded-for header to the externally-visible hostname and port. The rewrite looks like this:

rewrites: async () => [
    {
        source: "/api/:slug*",
        destination: "http://backend:8000/:slug*"
    }
]

The whole lot is running in a docker stack (which is where hostnames like backend come from) and I end up with headers like this:

host: backend:8000
x-forwarded-host: localhost:3000

I'm then emailing a link from the FastAPI application. I construct the URL like this:

@app.get("/verify")
async def verify(token: str):
    ...

@app.post("/signup")
async def signup(body: SignupRequest, request: Request) -> str:
    user = add_user(body.username, body.email)
    token = user.get_signup_token()
    url = request.url_for("verify").include_query_params(token=token)
    email_verification(body.email, url)
    return ""

I've set up FastAPI with root_path="/api" so that the path is rewritten correctly.

The resulting url is http://backend:8000/api/verify. I want it to be http://localhost:3000/api/verify (ie to have the actual hosted URL rather than the intra-docker-stack URL).

I've tried adding a middleware like this:

@app.middleware("http")
async def rewrite_host_header(request: Request, call_next):
    if "x-forwarded-host" in request.headers:
        request.headers["host"] = request.headers["x-forwarded-host"]
    return await call_next(request)

but this doesn't seem to make a difference. I've also tried adding request.url = request.url.replace(host=request.headers["x-forwarded-for"]) but this also doesn't change the output of request.url_for(...).

How am I meant to configure this so that URLs are emitted with the right scheme, hostname and port?

Edit to add: I've tried also setting X-Forwarded-Proto, X-Forwarded-Port, X-Forwarded-Prefix and X-Forwarded-For, making requests directly to FastAPI using curl and so cutting out the NextJS step. None of it makes any difference to the URLs that url_for() emits.

I have a FastAPI application that is behind a NextJS reverse proxy. I'm using NextJS rewrites, which sets the x-forwarded-for header to the externally-visible hostname and port. The rewrite looks like this:

rewrites: async () => [
    {
        source: "/api/:slug*",
        destination: "http://backend:8000/:slug*"
    }
]

The whole lot is running in a docker stack (which is where hostnames like backend come from) and I end up with headers like this:

host: backend:8000
x-forwarded-host: localhost:3000

I'm then emailing a link from the FastAPI application. I construct the URL like this:

@app.get("/verify")
async def verify(token: str):
    ...

@app.post("/signup")
async def signup(body: SignupRequest, request: Request) -> str:
    user = add_user(body.username, body.email)
    token = user.get_signup_token()
    url = request.url_for("verify").include_query_params(token=token)
    email_verification(body.email, url)
    return ""

I've set up FastAPI with root_path="/api" so that the path is rewritten correctly.

The resulting url is http://backend:8000/api/verify. I want it to be http://localhost:3000/api/verify (ie to have the actual hosted URL rather than the intra-docker-stack URL).

I've tried adding a middleware like this:

@app.middleware("http")
async def rewrite_host_header(request: Request, call_next):
    if "x-forwarded-host" in request.headers:
        request.headers["host"] = request.headers["x-forwarded-host"]
    return await call_next(request)

but this doesn't seem to make a difference. I've also tried adding request.url = request.url.replace(host=request.headers["x-forwarded-for"]) but this also doesn't change the output of request.url_for(...).

How am I meant to configure this so that URLs are emitted with the right scheme, hostname and port?

Edit to add: I've tried also setting X-Forwarded-Proto, X-Forwarded-Port, X-Forwarded-Prefix and X-Forwarded-For, making requests directly to FastAPI using curl and so cutting out the NextJS step. None of it makes any difference to the URLs that url_for() emits.

Share Improve this question edited Feb 3 at 19:51 Chris 34.7k10 gold badges100 silver badges239 bronze badges asked Feb 2 at 19:54 TomTom 8,0325 gold badges48 silver badges88 bronze badges 2
  • You may find code excerpts in this and this that might prove helpful to you. – Chris Commented Feb 3 at 11:53
  • Yep, that's what I ended up doing, thanks. Added middleware to set host from x-forwarded-for. – Tom Commented Feb 3 at 20:43
Add a comment  | 

1 Answer 1

Reset to default 0

I think the issue is that Uvicorn (if you're using it) does not trust proxy headers by default unless specified.

According to the FastAPI documentation about deploying FastAPI on Docker behind a proxy, you need to enable proxy headers.

Additionally, Starlette provides information about Uvicorn middleware for handling proxy header. The Uvicorn GitHub code also provides insight into how proxy headers are processed.

发布评论

评论列表(0)

  1. 暂无评论