FastAPI部署后url_for生成localhost而非域名URL的问题排查
解决FastAPI部署后url_for生成静态文件URL错误的问题
问题原因
生产环境中Nginx作为反向代理时,FastAPI无法获取外部访问的域名和协议信息,默认使用gunicorn绑定的内部地址(127.0.0.1:8000)生成URL。
解决步骤
1. 配置Nginx传递正确的请求头部
在Nginx的站点配置文件中,给反向代理的location块添加以下头部,让FastAPI能拿到外部的域名、IP和协议:
server { listen 80; server_name my_domain.com; location / { proxy_pass http://127.0.0.1:8000; # 传递外部主机名 proxy_set_header Host $host; # 传递客户端真实IP proxy_set_header X-Forwarded-For $remote_addr; # 传递访问协议(http/https) proxy_set_header X-Forwarded-Proto $scheme; # 传递请求路径 proxy_set_header X-Forwarded-Path $request_uri; } # 直接处理静态文件(可选,提升访问性能) location /static { alias /path/to/your/app/static; expires 30d; } }
修改后重启Nginx:
sudo systemctl restart nginx
2. 让FastAPI信任反向代理的头部
有两种实现方式:
方式一:启动gunicorn时指定root_path
启动gunicorn时添加--root-path参数,指定你的外部域名:
gunicorn main:app --workers 4 --bind 127.0.0.1:8000 --root-path=http://my_domain.com
方式二:添加FastAPI中间件
在FastAPI主文件(如main.py)中添加中间件,信任Nginx传递的代理头部:
from fastapi import FastAPI from fastapi.middleware.trustedhost import TrustedHostMiddleware from starlette.middleware.base import BaseHTTPMiddleware from starlette.requests import Request app = FastAPI() # 信任指定的外部域名 app.add_middleware(TrustedHostMiddleware, allowed_hosts=["my_domain.com", "www.my_domain.com"]) # 处理转发的头部信息 class ForwardedHeadersMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): scheme = request.headers.get("X-Forwarded-Proto", request.url.scheme) host = request.headers.get("X-Forwarded-Host", request.url.hostname) port = request.headers.get("X-Forwarded-Port") # 重构请求的基础URL base_port = int(port) if port else (443 if scheme == "https" else 80) request.scope["scheme"] = scheme request.scope["server"] = (host, base_port) response = await call_next(request) return response app.add_middleware(ForwardedHeadersMiddleware)
3. 模板中强制生成绝对URL
在Jinja2模板的url_for调用里添加_external=True,确保生成包含域名的绝对URL:
<script src="{{ url_for('static', path='js/login_signup.js', _external=True) }}"></script>
完成以上配置后,重启gunicorn服务,url_for就能正确生成指向http://my_domain.com/static/js/login_signup.js的URL。
内容的提问来源于stack exchange,提问作者Hamza Farooq
相关产品推荐
相关产品推荐

