我为某个运行良好的DRF端点设置分页 - 但是当我在使用HTTPS的服务器上部署时,链接到下一个&之前的页面由http://
而不是https://
组成。这会导致浏览器阻止对下一页/上一页的请求。
我已经使用HTTPS仔细检查了初始请求,并且this question的第二个回答表明它应该在形成的URL中使用HTTPS,因为请求来自HTTPS。
对同一个问题的第一个答案也没有帮助 - 我将X-Forwarded-Proto
行添加到我的nginx配置并重新加载,但无济于事。
The DRF docs提到reverse()应该表现为基本Django反向,但是很明显初始请求是HTTPS而返回的URL是HTTP。
以下是一些显示初始请求(https://<domain>.com/api/leaderboard/
)的屏幕截图:
包含next: http://<domain>.com/api/leaderboard/?page=2
)的回复:
我认为这是一个简单的设置,但是在搜索了这个网站和DRF网站后,我们找不到任何东西。
这是我的nginx配置:
location / {
# proxy_pass http://127.0.0.1:9900;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
add_header P3P 'CP="ALL DSP COR PSAa PSDa OUR NOR ONL UNI COM NAV"';
root /opt/app/client/dist;
index index.html index.htm;
}
This question包含一个非常详细的答案,但最终表示网址是使用与请求相同的协议形成的,这似乎不是这里的情况。我需要设置Django SECURE_PROXY_SSL_HEADER吗?鉴于警告说它可能不安全,我不确定。
答案 0 :(得分:5)
我是否需要设置Django SECURE_PROXY_SSL_HEADER?鉴于警告可能不安全,我不确定。
是的,你这样做。 但是,你需要注意你在做什么。特别要确保它从外面放下X-Forwarded-Proto。
答案 1 :(得分:3)
由于这是google搜索结果中出现的第一篇SO帖子,所以我认为分享我如何解决它会很有用。我的软件具有Kubernetes风格,但在逻辑上并没有什么不同。
我使用的是坐在Django前面的Kubernetes入口控制器,所以情况可能与您有所不同,但是我将总结我的上下文,以便您查看它是否对您有用:
所以我遇到了与OP相同的问题,即使我使用http
到达api端点,来自DRF的分页链接也始终为https
。如果您设置了Django REST框架(DRF)随附的浏览器API,并转到api根页面,则可以更清楚地看到这一点。我看到DRF生成的所有链接都是http
,无论我访问网站时使用什么协议。
按从外部世界到Django的顺序排列的堆栈:
settings.py
并开始处理请求nginx.conf
。如果您不知道该怎么做:首先用kuberctl get pods -n <namespace of your ingress controller>
找出豆荚名称,写下该名称,然后用kubectl exec -it -n ingress_controller_namespace ingress_controller_pod_name cat /etc/nginx/nginx.conf > nginx.conf
转储文件。nginx.conf
,检查您的网站域的proxy_set_header X-Forwarded-Proto $scheme;
部分中是否有location
,或是否正确设置了代理标头X-Forwarded-Proto
的类似内容。默认情况下,Kubernetes nginx入口控制器应该已经为您提供了这一行(或等效功能)。--forwarded-allow-ips="*"
,或者如果您知道nginx服务器IP,则可以限制为该值,以便gunicorn为您转发标头,否则gunicorn会剥离这些标题。因此,您最终得到像gunicorn django_server.wsgi:application --forwarded-allow-ips="*" --workers=${PROPER_WORKER_NUM} --log-level info --bind 0.0.0.0:8001
这样的命令。通过指定workers=4
可以有4个工作线程,通常取决于服务器上的CPU。 --log-level info
仅用于调试目的,是可选的。SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
中包含settings.py
,其他答案也提到了这一点。您可能想知道为什么在nginx中,标题HTTP_
是前缀X-Forwarded-Proto
。这是因为WSGI会将前缀添加到它可以识别的标头中。该行基本上说,如果标头HTTP_X_FORWARDED_PROTO
等于字符串"https"
,则Django会将请求识别为安全请求。这会影响Django中的几种行为,例如您将获得request.is_secure == True
,request.build_absolute_uri(None) == 'https://...'
,最重要的是,Django REST Framework分页链接现在将使用https
! (只要您确实通过https
击中了api)好的,现在您可以再次测试。如果DRF现在为您提供https-恭喜。或者,如果您和我一样,在尝试以上之后,仍然没有运气-DRF仍会生成该死的http
链接。当我像地狱一样调试时,我想分享一些提示:
如果您拥有print()
并有权访问服务器日志,则通过DEBUG=True
在Django中打印以下值,或者将它们传递到模板上下文并在html页面中显示,如果这样可以使您更容易在启用SSL的生产环境中进行测试。
request.is_secure()
:如果您无法使DRF使用http
,则很可能您会获得False
。request.META
提供了Django收到的所有标头。标头HTTP_X_FORWARDED_PROTO
是否出现?它有什么价值?
HTTP_X_FORWARDED_PROTO
的值是http,https
,这告诉我它以某种方式具有重复的值,并且我可能有{{1 }}设置两次,然后宾果游戏!默认情况下,K8入口控制器已经有这行,并且由于我通过proxy_set_header
再次添加了它,所以现在我总共有两行location-snippet
。删除代码段后,DRF会显示proxy_set_header X-Forwarded-Proto $scheme;
,我非常高兴能够完成此操作。并不是那么简单,因为我认为https
将覆盖并“设置”标头值。但似乎只是继续追加。