2017-07-03 88 views
3

为什么django忽略HTTP_X_FORWARDED_PROTO,如果它通过线路?为什么django忽略HTTP_X_FORWARDED_PROTO而不是在测试中?

我加入的settings.xml以下配置:

# make sure we know when we are secure when we are behind a proxy 
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https') 

我做了一个测试,测试,如果

def testHttpSupport(self): 
    url = reverse('configuration-list') 
    response = self.client.get(url, HTTP_X_FORWARDED_PROTO='https') 
    cfg = response.data[0] 
    cfg_url = cfg['url'] 
    self.assertTrue(cfg_url.startswith('https')) 

能正常工作。返回对象的url以https开头。

但是如果我尝试:

curl -v -H 'HTTP_X_FORWARDED_PROTO: https' http://localhost:8000/api/users/ 
... 
> GET /api/users/ HTTP/1.1 
> Host: localhost:8000 
> User-Agent: curl/7.51.0 
> Accept: */* 
> HTTP_X_FORWARDED_PROTO: https 
> 
* HTTP 1.0, assume close after body 
< HTTP/1.0 200 OK 
< Date: Mon, 03 Jul 2017 16:22:04 GMT 
< Server: WSGIServer/0.2 CPython/3.6.1 
< Content-Type: application/json 
< Allow: GET, POST, OPTIONS 
< Vary: Accept, Cookie 
< X-Frame-Options: SAMEORIGIN 
< Content-Length: 197 
< 
* Curl_http_done: called premature == 0 
* Closing connection 0 
[{"url":"http://localhost:8000/api/users/1/",... 

怎么就没有返回的“https://”网址的基础喜欢在我的单元测试?

回答

4

问题是标题名称。当通过WSGI服务器访问Django的,你应该使用X-Forwarded-Proto头,而不是HTTP_X_FORWARDED_PROTO

curl -v -H 'X-Forwarded-Proto: https' http://localhost:8000/api/users/ 

的WSGI协议规定,有关CGI规范必须遵循的,这说:

荟萃如果使用的协议是HTTP,那么名称以'HTTP_'开头的变量包含从客户端请求标头字段读取的 值。 将HTTP标题字段名转换为大写,将所有 出现的“ - ”替换为“_”,并将'HTTP_'前置为 以提供元变量名称。

source

所以每当你正在使用WSGI服务器,之前在给Django是通过X-Forwarded-Proto头被自动转换为HTTP_X_FORWARDED_PROTO。当您传入HTTP_X_FORWARDED_PROTO标题时,HTTP_仍必须根据规范进行预设。因此,你最终在Django中得到一个名为HTTP_HTTP_X_FORWARDED_PROTO的头文件。

self.client不是WSGI服务器,通过kwargs传入的值直接插入到WSGI环境中,无需任何处理。因此,在这种情况下,你必须自己做转换和实际使用HTTP_X_FORWARDED_PROTO键:

CGI规范

通过**额外发送应遵循CGI规范的标头。例如,模拟与从浏览器发送到服务器的HTTP请求中发送的不同的“主机”头文件应该作为HTTP_HOST传递。

source