在 nginx 反向代理后面处理 flask url_for

Handling flask url_for behind nginx reverse proxy

我有一个使用 nginx 进行反向 proxy/ssl 终止的 Flask 应用程序,但是在使用 url_for 并在 Flask 中重定向时我 运行 遇到了麻烦。

nginx.conf条目:

location /flaskapp {
  proxy_pass http://myapp:8080/;
  proxy_set_header Host $http_host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

这个想法是用户导航到

https://localhost:port/flaskapp/some/location/here

并且应该作为

传递给烧瓶

http://localhost:8080/some/location/here

这在导航到定义的路线时相当有效,但是如果路线有 redirect(url_for('another_page')),浏览器将定向到

http://localhost:8080/another_page

失败了,当我真正想去的 URL 是:

https://localhost:port/flaskapp/another_page

我已经针对类似情况尝试了其他几个答案,但 none 似乎正在做我在这里所做的事情。我曾尝试使用 _external=True、设置 app.config['APPLICATION_ROOT'] = '/flaskapp' 以及 nginx.conf 中不同 proxy_set_header 命令的多次迭代,但没有成功。

更复杂的是,我的 Flask 应用程序正在使用 flask-login 和 CSRF cookie。当我尝试设置 APPLICATION_ROOT 时,应用程序停止考虑由 flask-login 设置的 CSRF cookie 有效,我认为这与起源有关。

所以我的问题是,我该怎么做才能让 flask 向客户端返回 redirect() 时,nginx 明白给定的 URL 需要写入 flaskapp进去了吗?

我设法通过一些更改修复它。

更改 1. 将 /flaskapp 添加到我的 flask 应用程序的路由中。这消除了 URL 重写的需要并大大简化了事情。

更改 2。nginx.conf 更改。我在位置块中添加了 logc 以将 http 请求重定向为 https,新的 conf:

location /flaskapp {
  proxy_pass http://myapp:8080/;
  proxy_set_header Host $http_host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  # New configs below
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-Proto $scheme;
  # Makes flask redirects use https, not http.
  proxy_redirect http://$http_host/ https://$http_host/;
}

虽然我没有"solve"引入基于已知前缀的条件重写的问题,因为我只需要这个应用程序的一个前缀,所以将它烘焙到路由中是一种可接受的解决方案。

在你的情况下,我认为正确的做法是使用 werkzeug 的 ProxyFix 中间件,并让你的 nginx 代理设置适当的要求 headers(特别是 X-Forwarded-Prefix)。

https://werkzeug.palletsprojects.com/en/0.15.x/middleware/proxy_fix/#module-werkzeug.middleware.proxy_fix

这应该会使 url_for 像您预期的那样工作。

编辑:@Michael P 的回答片段

from werkzeug.middleware.proxy_fix import ProxyFix
app = Flask(__name__)
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_host=1)