I'd like to know the following
- How does Starlette set the "url" property in the Request object - especially when operated behind a NGINX proxy.
- How can
request.urlbe manipulated on the NGINX level -- setting proxy headers doesn't modify it at all? - How can
request.urlbe manipulated via a Starlette Middleware -- somehow what I did doesn't have any effect?
The setting is like this:
I have a FastAPI app running behind a NGINX proxy. Via the browser, I send requests to NGINX via HTTPS (https://www.example.com) , but whatever I do, request.url on Starlette's side is always http://www.example.com.
I made a small FastAPI endpoint for demonstration purposes
@app.get("/test")def some_test(request: Request): return {"request.url": request.url,"request['headers']": request["headers"],"request.client": request.client}and in the following screenshots I show what I get (domain is anonymized; set to xyz):
- I call in the browser
https://www.example.com/test - In the console, I see that properly the request is issues to
https://www.example.com/test - But when looking at Starlette's
Request.url, it sayshttp://www.example.com/test
Is this behaviour how it should be? In the screenshot I also print the host and x-forwarded-proto and x-forwarded-schema which I set the NGINX config to HTTPS, but the object Request isn't modified at all by that.
What can I do to correct this on the NGINX or FastAPI/Starlette level?
- I already tried setting various commands like
with no success at all.proxy_set_header Upgrade $http_upgrade;proxy_set_header Host $http_host;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_set_header X-Forwarded-Scheme $scheme; - I tried to write a custom Starlette Middleware (I know that's quite ugly, but I wanted to try this out to better understand, what's going on)
but this also doesn't modify thefrom fastapi import Requestfrom starlette.datastructures import URL@app.middleware("http")async def some_middlware(request: Request, call_next): if "/test" in str(request.url): print(f"before {request.url}") request._url = URL(str(request.url).replace("http", "https")) print(f"after {request.url}") response = await call_next(request) return responserequest.urlshown in the response.