TL;DR = Nginx 没有 Docker 映射端口的概念,需要对它们进行硬编码。
类似问题:https://serverfault.com/questions/577370/how-can-i-use-environment-variables-in-nginx-conf
Django 要求 HTTP 请求标头包含主机所需的信息(下面的代码 sn-p)。这种情况下需要从 Nginx 传入:
location / {
proxy_pass http://web:7000;
proxy_set_header Host $host:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
请注意端口的不幸硬编码:$host:8080。 “外部”问题是 Nginx 容器的端口使用 Docker 映射到 8080 (-p 80:8080),因此它不知道它实际上是在端口 8080 上运行; Nginx 检测到自己在 80 端口上运行。
有一个 SOCIAL_AUTH_LOGIN_REDIRECT_URL 的 Django 设置,但像这样指定它:
SOCIAL_AUTH_LOGIN_REDIRECT_URL = 'http://localhost:8080/complete/google-oauth2/'
在尝试通过 Google 进行身份验证时导致这种情况发生:
AuthMissingParameter at /complete/google-oauth2/
缺少所需的参数状态
请求方法:GET
请求网址:http://localhost:8080/complete/google-oauth2/
Django 版本:2.1.5
异常类型:AuthMissingParameter
异常值:
缺少所需的参数状态
异常位置:/usr/local/lib/python3.6/site-packages/social_core/backends/oauth.py 在 validate_state,第 88 行
Python 可执行文件:/usr/local/bin/python
Python 版本:3.6.10
因此,我目前唯一的解决方案是在构建 Docker 映像时将端口烘焙到 Nginx 配置中。
Django 2.1.5 版本获取主机代码:
def _get_raw_host(self):
"""
Return the HTTP host using the environment or request headers. Skip
allowed hosts protection, so may return an insecure host.
"""
# We try three options, in order of decreasing preference.
if settings.USE_X_FORWARDED_HOST and (
'HTTP_X_FORWARDED_HOST' in self.META):
host = self.META['HTTP_X_FORWARDED_HOST']
elif 'HTTP_HOST' in self.META:
host = self.META['HTTP_HOST']
else:
# Reconstruct the host using the algorithm from PEP 333.
host = self.META['SERVER_NAME']
server_port = self.get_port()
if server_port != ('443' if self.is_secure() else '80'):
host = '%s:%s' % (host, server_port)
return host