Django的HttpResponseRedirect是http而不是https。

12

我的服务器运行 Django + Gunicorn + nginx。

我已添加了 SSL 证书并配置了 nginx 将 http 重定向到 https。当收到 https 请求时,nginx 会将其作为 http 传递给 Gunicorn。

我的程序有时会返回 HttpResponseRedirect,浏览器会获取重定向响应并以 http 方式重新请求,因此 nginx 会重定向到 https。

我该如何避免这种情况?我该如何配置服务器,使第一次重定向直接指向一个 https URL?


我实际上做了同样的事情。告诉 Nginx 将所有 HTTP 请求重定向到 HTTPS,并且它运行得非常好。 - Jbertrand
1个回答

16
在 nginx 配置文件中(在 location 块内部),指定以下内容:
proxy_redirect off;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect 告诉nginx,如果后端返回一个HTTP重定向,它应该保持不变。默认情况下,nginx假定后端是愚蠢的,并试图变得聪明; 如果后端返回一个HTTP重定向,说“重定向到 http://localhost:8000/somewhere”,nginx将其替换为类似于 http://yourowndomain.com/somewhere"。但Django并不愚蠢(或者可以配置为不愚蠢)。
Django不知道请求是通过HTTPS还是普通的HTTP进行的; nginx知道,但是随后发送到Django后端的请求始终是普通HTTP。我们使用HTTP头部X-Forwarded-Proto告诉nginx传递这些信息,以使相关的Django功能如request.is_secure()正常工作。您还需要在settings.py中设置SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

我需要设置nginx和Django吗,还是只需要设置nginx? - permike
我不确定你的意思。最好的方法是让Django将重定向返回为相对URL,即“/target”,而不是“http://domain/target”。 - Antonis Christofides
我的意思是,按照你所说的设置了nginx之后,我是否还需要设置Django的settings.py文件,或者这只是对其他功能的改进。总之,你的回答真的很有帮助,谢谢! - permike
@permike 我认为这可能对更多人有用,所以我在 https://djangodeployment.com/2017/01/24/fix-djangos-https-redirects-nginx/ 上写了一篇博客。 - Antonis Christofides
@AntonisChristofides 我已经按照您的描述尝试了,但在我的请求中,它显示HTTP_X_FORWARDED_PROTO ='http,http'。这里可能出了什么问题?其他所有内容都显示为https,包括URL。 - Alex
@Alex 没有想法,但你需要非常精确。你的请求没有“显示”任何东西,我不相信有任何HTTP_X_FORWARDED_PROTO ='http,http'完全一样的地方。虽然我怀疑你的意思是请求包括值为http,httpHTTP_X_FORWARDED_PROTO头,但当我们可以掌握事实时,我们不应该基于猜测或推测来工作。如果你准确地表达它,你很可能会自己找到解决方案。 - Antonis Christofides

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接