Flask 在 gunicorn + nginx 下的 redirect(url_for) 错误
我在我的Flask应用中遇到了一个关于重定向(redirect(url_for))的问题。
每当我使用重定向,比如写成redirect(url_for("index"))时,应用就会从domain.com/app跳转到ip-addr/app,而这个ip-addr是我自己电脑的IP地址,而不是服务器的地址。
这让我非常困惑,我不知道问题到底出在哪里,因为这个问题只在服务器上出现,而在本地测试时没有任何问题。
具体情况:
我使用的是这里找到的反向代理设置 http://flask.pocoo.org/snippets/35/。我的nginx配置是这样的:
location /app {
proxy_set_header X-Script-Name /app;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Host $proxy_add_x_forwarded_for;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_connect_timeout 60;
proxy_read_timeout 60;
proxy_pass http://localhost:8000/;
}
我用gunicorn来运行我的Flask应用,作为一个upstart任务。有没有什么提示可以帮助我解决这个问题?
补充:
我稍微查了一下,发现这个git报告也有类似的问题,https://github.com/omab/django-social-auth/issues/157。
Nginx - Gunicorn通过本地地址(127.0.0.1:1234)服务给Nginx。不幸的是,当我通过社交平台进行身份验证时,社交认证发送的重定向URL是127.0.0.1:1234/twitter/complete,这显然无法被客户端的浏览器解析。
看起来我的Flask应用没有收到更新重定向路由的通知。
5 个回答
我遇到过类似的问题。当我用gunicorn运行我的服务器时,它在执行@return redirect(url_for(‘login’))的时候崩溃了。想要解决这个问题,可以去看看这个链接:Flask应用在用gunicorn和nginx运行时在重定向时崩溃
我在这个问题上花了两个晚上,最后用这个方法解决了它:http://blog.macuyiko.com/post/2016/fixing-flask-url_for-when-behind-mod_proxy.html,我的代理设置如下:
ProxyPass /crm http://localhost:5013/
ProxyPassReverse /crm http://localhost:5013/
而且ReverseProxy类运行得非常好,关键在于“script_name”,这个在这里的代码片段中并没有包含:http://flask.pocoo.org/snippets/35/。我猜flask页面上的代码片段是适用于ngnix的,而这个是针对apache2代理的。如果有人再次遇到同样的问题,希望这能帮到你(包括未来的我)
我也遇到过同样的问题。你的解决方案需要让应用程序知道它运行在哪个域名下,这就需要为每个环境设置一个配置变量。我发现这里的解决办法其实是重新写nginx的proxy_pass头部,像这样:
location /api {
# Define the location of the proxy server to send the request to
proxy_pass http://web:8000;
# Redefine the header fields that NGINX sends to the upstream server
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Define the maximum file size on file uploads
client_max_body_size 5M;
}
我找到了解决办法。我需要对所有的重定向使用 redirect(url_for(location, _external=True))
。
看起来 url_for(x, _external=True)
会把我在 nginx 里设置的所有变量都用来构建网址,而 url_for(x)
则没有这样做。
这个方法在服务器和本地开发中都有效。
加上 include proxy_params
解决了我的问题。
location / {
proxy_pass http://...;
include proxy_params;
}