Django的request.META.get('wsgi.url_scheme')返回http而不是https。

4
我发现当我看到request.META.get('wsgi.url_scheme')返回http而我的request.scheme返回https时,感觉很奇怪。 这是我的请求对象字典的样子:
{'session': <django.contrib.sessions.backends.cache.SessionStore object at 0x7fec7ff57a90>, '_post': <QueryDict: {u'notify_page': [u'https://example.com/my/deposit/success/'], u'bank': [u'CMB'], u'transaction_id': [u'2017051111382524291123'], u'payment_type': [u'1']}>, 'COOKIES': {'csrftoken': 'Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I', 'sessionid': 'uuoxols288i9018fw11coz1yvvwn9ndh', 'auth_req': ''}, '_post_parse_error': False, 'resolver_match': ResolverMatch(func=pay.views.perform, args=(), kwargs={}, url_name=None, app_names=[], namespaces=[]), 'user_agent': <SimpleLazyObject: <function <lambda> at 0x7fec842d2c80>>, '_stream': <_io.BytesIO object at 0x7fec84017cb0>, '_body': 'transaction_id=2017051111382524291123&notify_page=https%3A%2F%2Fexample.com%2Fmy%2Fdeposit%2Fsuccess%2F&bank=CMB&payment_type=1', '_files': <MultiValueDict: {}>, '_read_started': True, 'META': {'HTTP_REFERER': 'https://example.com/my/deposit', 'HTTP_X_FORWARDED_SSL': 'on', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'SCRIPT_NAME': u'', 'REQUEST_METHOD': 'POST', 'PATH_INFO': u'/payment/', 'HTTP_ORIGIN': 'https://example.com', 'SERVER_PROTOCOL': 'HTTP/1.0', 'QUERY_STRING': '', 'HTTP_X_REAL_IP': '180.232.79.194', 'CONTENT_LENGTH': '127', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36', 'HTTP_CONNECTION': 'close', 'HTTP_COOKIE': 'csrftoken=Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I; auth_req=; sessionid=uuoxols288i9018fw11coz1yvvwn9ndh', 'SERVER_NAME': '0.0.0.0', 'REMOTE_ADDR': '172.17.0.2', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '8000', 'REMOTE_PORT': '57938', 'HTTP_X_FORWARDED_PROTO': 'https', 'wsgi.input': <gunicorn.http.body.Body object at 0x7fec84220750>, 'HTTP_HOST': 'example-backend.com', 'wsgi.multithread': True, 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'wsgi.version': (1, 0), 'RAW_URI': '/payment/', 'wsgi.run_once': False, 'wsgi.errors': <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fec84036550>, 'wsgi.multiprocess': True, 'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8', 'gunicorn.socket': <socket at 0x7fec7ff95590 fileno=14 sock=172.17.0.6:8000 peer=172.17.0.2:57938>, 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'HTTP_X_FORWARDED_FOR': '180.232.79.194', 'wsgi.file_wrapper': <class 'gunicorn.http.wsgi.FileWrapper'>, u'CSRF_COOKIE': u'Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br'}, 'environ': {'HTTP_REFERER': 'https://example.com/my/deposit', 'HTTP_X_FORWARDED_SSL': 'on', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'SCRIPT_NAME': u'', 'REQUEST_METHOD': 'POST', 'PATH_INFO': u'/payment/', 'HTTP_ORIGIN': 'https://example.com', 'SERVER_PROTOCOL': 'HTTP/1.0', 'QUERY_STRING': '', 'HTTP_X_REAL_IP': '180.232.79.194', 'CONTENT_LENGTH': '127', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36', 'HTTP_CONNECTION': 'close', 'HTTP_COOKIE': 'csrftoken=Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I; auth_req=; sessionid=uuoxols288i9018fw11coz1yvvwn9ndh', 'SERVER_NAME': '0.0.0.0', 'REMOTE_ADDR': '172.17.0.2', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '8000', 'REMOTE_PORT': '57938', 'HTTP_X_FORWARDED_PROTO': 'https', 'wsgi.input': <gunicorn.http.body.Body object at 0x7fec84220750>, 'HTTP_HOST': 'example-backend.com', 'wsgi.multithread': True, 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'wsgi.version': (1, 0), 'RAW_URI': '/payment/', 'wsgi.run_once': False, 'wsgi.errors': <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fec84036550>, 'wsgi.multiprocess': True, 'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8', 'gunicorn.socket': <socket at 0x7fec7ff95590 fileno=14 sock=172.17.0.6:8000 peer=172.17.0.2:57938>, 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'HTTP_X_FORWARDED_FOR': '180.232.79.194', 'wsgi.file_wrapper': <class 'gunicorn.http.wsgi.FileWrapper'>, u'CSRF_COOKIE': u'Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br'}, 'path_info': u'/payment/', '_messages': <django.contrib.messages.storage.fallback.FallbackStorage object at 0x7fec7ffccf10>, 'LANGUAGE_CODE': u'en', 'path': u'/payment/', 'method': 'POST', 'user': <SimpleLazyObject: <function <lambda> at 0x7fec842d2f50>>}

这是请求META返回的内容

{'HTTP_REFERER': 'https://example.com/my/deposit', 'HTTP_X_FORWARDED_SSL': 'on', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'SCRIPT_NAME': u'', 'REQUEST_METHOD': 'POST', 'PATH_INFO': u'/payment/', 'HTTP_ORIGIN': 'https://example.com', 'SERVER_PROTOCOL': 'HTTP/1.0', 'QUERY_STRING': '', 'HTTP_X_REAL_IP': '180.232.79.194', 'CONTENT_LENGTH': '127', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36', 'HTTP_CONNECTION': 'close', 'HTTP_COOKIE': 'csrftoken=Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I; auth_req=; sessionid=uuoxols288i9018fw11coz1yvvwn9ndh', 'SERVER_NAME': '0.0.0.0', 'REMOTE_ADDR': '172.17.0.2', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '8000', 'REMOTE_PORT': '57938', 'HTTP_X_FORWARDED_PROTO': 'https', 'wsgi.input': <gunicorn.http.body.Body object at 0x7fec84220750>, 'HTTP_HOST': 'example-backend.com', 'wsgi.multithread': True, 'HTTP_UPGRADE_INSECURE_REQUESTS': '1', 'HTTP_CACHE_CONTROL': 'max-age=0', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'wsgi.version': (1, 0), 'RAW_URI': '/payment/', 'wsgi.run_once': False, 'wsgi.errors': <gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fec84036550>, 'wsgi.multiprocess': True, 'HTTP_ACCEPT_LANGUAGE': 'en-US,en;q=0.8', 'gunicorn.socket': <socket at 0x7fec7ff95590 fileno=14 sock=172.17.0.6:8000 peer=172.17.0.2:57938>, 'CONTENT_TYPE': 'application/x-www-form-urlencoded', 'HTTP_X_FORWARDED_FOR': '180.232.79.194', 'wsgi.file_wrapper': <class 'gunicorn.http.wsgi.FileWrapper'>, u'CSRF_COOKIE': u'Y3FRFDfvK6U2dkgVr3KarzJE6GUdAZ1I', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br'}

我的Nginx

ssl_certificate     /etc/nginx/ssl/example.com/example.crt;
ssl_certificate_key /etc/nginx/ssl/example.com/example.key;

server {

    listen 443 ssl;
    server_name example.com;
    charset utf-8;
    access_log /var/log/nginx/access.django.log;
    error_log /var/log/nginx/error.django.log;


    location /static {
        alias /usr/src/app/static;
    }

    location /upload { # IMPORTANT! To allow the CDN to access our files
        alias /usr/src/app/upload;
        expires 240h;  # 10 days
        add_header Cache-Control "public";  # to allow the CDN to cache our files
    }

    location / {
        proxy_pass http://django:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

我知道为了解决我的问题,我只需要将所有的request.META.get('wsgi.url_scheme')替换为 request.scheme,但也许有人能够解释一下为什么会发生这种情况。
1个回答

6

简短版: 您应将您的nginx服务器地址添加到gunicorn设置中的forwarded_allow_ips

详细版:

根据request.META值,我假设nginx和您的django应用程序部署在不同的服务器上。

因此,nginx接收到HTTPS请求,将X-Forwarded-Proto标头设置为https并将请求传递给gunicorn。

request.scheme由django设置为https,因为有X-Forwarded-Proto标头,而且您可能在django配置中有这样一行:

SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

wsgi.url_scheme是由gunicorn设置的。如果设置中允许使用secure_scheme_headersforwarded_allow_ips,则它将从同一标头(X-Forwarded-Proto)获取值。默认情况下,X-Forwarded-Proto包含在secure_scheme_headers中。但是forwarded_allow_ips的默认值为127.0.0.1。因此,gunicorn会忽略该标头,并将wsgi.url_scheme设置为http。将forwarded_allow_ips设置为您的nginx服务器的地址即可解决此问题。

这个forwarded_allow_ips设置非常棘手。当您在同一台服务器上部署nginx和django时,很难注意到它。然后,您转移到多服务器设置并注意到您的重定向和绝对URL正在使用HTTP。

顺便说一句,如果SECURE_PROXY_SSL_HEADER未设置,则requests.scheme将使用wsgi.url_scheme的值。因此,只要正确设置了wsgi.url_scheme,我不知道为什么您需要SECURE_PROXY_SSL_HEADER

此外,您可能希望使用更易于/标准/可靠的方法来检查HTTPS:HttpRequest.is_secure()


我在使用gunicorn的Azure应用服务中遇到了这个问题,我该如何将wsgi.url_scheme设置为https。服务器和gunicorn都在同一位置运行。 - Rahul Rajput

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