python - 为什么 django 忽略线路中的 HTTP_X_FORWARDED_PROTO 而不是在测试中?

标签 python django https django-rest-framework

为什么 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://”的 url?

最佳答案

问题是标题名称。通过 WSGI 服务器访问 Django 时,您应该使用 X-Forwarded-Proto header 而不是 HTTP_X_FORWARDED_PROTO:

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

WSGI 协议(protocol)声明必须遵循相关的 CGI 规范,其中说:

Meta-variables with names beginning with 'HTTP_' contain values read from the client request header fields, if the protocol used is HTTP. The HTTP header field name is converted to upper case, has all occurrences of "-" replaced with "_" and has 'HTTP_' prepended to give the meta-variable name.

( source )

因此,无论何时您使用 WSGI 服务器,X-Forwarded-Proto header 都会在传递给 Django 之前自动转换为 HTTP_X_FORWARDED_PROTO。当您改为传入 HTTP_X_FORWARDED_PROTO header 时,根据规范,HTTP_ 仍必须放在前面。因此,您最终会在 Django 中得到一个名为 HTTP_HTTP_X_FORWARDED_PROTO 的 header 。

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

CGI specification

The headers sent via **extra should follow CGI specification. For example, emulating a different “Host” header as sent in the HTTP request from the browser to the server should be passed as HTTP_HOST.

( source )

关于python - 为什么 django 忽略线路中的 HTTP_X_FORWARDED_PROTO 而不是在测试中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44890448/

相关文章:

Python optparse、默认值和显式选项

python - 获取一个基类的所有子类作为基类的class属性

python - 尝试学习 while 循环出现意外缩进和语法错误? (Python)

django-rest-framework序列化器如何获取用户id

ssl - 支持TLS1.2/SNI的HTTP负载测试工具

node.js - HAPI SSL 错误 :0906D06C:PEM routines:PEM_read_bio:no start line

python - Scrapy IO错误: [Errno 22] invalid mode ('wb' ) or filename

python - Django-Debug-Toolbar 未显示(不允许的 MIME 类型)

python - 在 Django 中验证上传文件类型

linux - 在 Centos6 上的 Apache 中设置 SSL