缺少 django、nginx 和 gunicorn 的自定义标头
Posted
技术标签:
【中文标题】缺少 django、nginx 和 gunicorn 的自定义标头【英文标题】:Missing custom header with django, nginx and gunicorn 【发布时间】:2011-12-22 02:29:12 【问题描述】:免责声明:
我正在一个项目中工作,其中存在一个“巨大”的 web 应用程序,它有一个用于移动设备的 api,因此更改 api 不是一种选择。
这个应用程序是很久以前开发的,已经有几个开发者在开发它,
话虽如此,问题是这样的;
在这个网站的移动API中(只是查看而不是返回json数据),代码正在寻找一个令牌,但在请求的标头中:
token = request.META.get('HTTP_TOKEN')
当我在本地测试这个 api 时,工作正常,但在生产中却不行,所以,我试图弄清楚发生了什么并发现了这个:
django 将标头,甚至自定义标头转换为 request.META 中的键,我使用 urllib2 和 requests 来测试 api,生产中的问题是在生产服务器中 request.META 从来没有一个名为 HTTP_TOKEN 的键,所以,做一点调试我认真地认为问题出在我们为 django 应用程序提供服务的方式上。
我们正在使用 django1.3、nginx、gunicorn、virtualenvwrapper、python2.7。
我的主要嫌疑人是 nginx,我认为,以某种方式 nginx 接收到标头但不将其转发给 django,我尝试对此进行一些研究,但我只从 nginx 中找到有关安全标头和自定义标头的信息,但是我没有找到有关如何告诉 nginx 允许该标头并且不删除它的文档或其他内容。
我这里需要帮助,首先是测试nginx是否接收到header,但是我对nginx了解一点,不知道如何告诉它记录请求的headers。
谢谢
更新
nginx conf file
【问题讨论】:
你能证明这个假设吗?记录来自 nginx 和 django 的请求,并确保 HTTP 标头中确实存在差异。 部分是问题所在,在测试中,使用 urllib2 的脚本和请求我定义了我发送的标头,在我打印收到的标头的视图中,在开发服务器中,标头很好,但是在生产中 django 没有收到 HTTP_TOKEN 标头。 我正在寻找一种方法来对 nginx 打印请求标头说,但文档有点糟糕 请求头是字面意义上的HTTP_TOKEN吗?还是只是代币? TOKEN 但 django 附加 HTTP_ 【参考方案1】:我认为这是你需要的:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$http_http_token" "$upstream_http_http_token"'
记录正在发生的事情。
您可能会更深入地查看上游代理模块的 proxy_set_header 部分,以了解如何传递您需要的标头。
您可以在此处找到文档:
http://wiki.nginx.org/HttpLogModule http://wiki.nginx.org/NginxHttpUpstreamModule http://wiki.nginx.org/NginxHttpProxyModule#proxy_set_header http://wiki.nginx.org/HttpProxyModule#proxy_pass_request_headers最后一个条目似乎表明nginx默认通过了大多数标头
【讨论】:
【参考方案2】:如果使用 uwsgi_pass 访问 Django,则在适当的位置...
# All request headers should be passed on by default
# Make sure "Token" response header is passed to user
uwsgi_pass_header Token;
如果使用 fastcgi_pass 访问 Django,则在适当的位置...
# All request headers should be passed on by default
# Make sure "Token" response header is passed to user
fastcgi_pass_header Token;
如果使用 proxy_pass 访问 Django,则在适当的位置...
# All request headers should be passed on by default
# but we can make sure "Token" request header is passed to Django
proxy_set_header Token $http_token;
# Make sure "Token" response header is passed to user
proxy_pass_header Token;
这些应该有助于消除 Nginx 没有从您的问题中传递信息的可能性。
【讨论】:
假设您的意思是“gunicorn 或 ...”,那么答案是这些是 nginx 指令。无处不在他们之前给了你一些链接。 有趣的是,在使用 uwsgi_pass_header 时,我个人在传递名称包含下划线的标头时遇到了问题。例如,当使用 AUTHTOKEN 时,标头 AUTH_TOKEN 永远不会到达 Django!【参考方案3】:我没有找到真正的答案,但能够解决。我在使用 RFC 标准标头 if-none-match 和 if-modified-since 时遇到了同样的问题,因此我的解决方案针对这些标头进行了测试。
添加到我的 nginx 配置中:
uwsgi_param HTTP_IF_NONE_MATCH $http_if_none_match;
uwsgi_param HTTP_IF_MODIFIED_SINCE $http_if_modified_since;
我无法解释为什么 nginx 默认拒绝将这些标头传递给 uwsgi。这个配置强制它。页面现在会根据需要生成 304。
对于关于非标准“令牌”标头的原始问题,这应该可以解决问题:
uwsgi_param HTTP_TOKEN $http_token;
【讨论】:
【参考方案4】:在您的 nginx 配置文件(例如 mysite_nginx.conf)的 server 部分中添加此参数:uwsgi_pass_request_headers on;
。
例如:
server
# the port your site will be served on
listen 8000;
...
underscores_in_headers on;
如果通过uwsgi_pass访问Django,则需要在location部分添加uwsgi_pass_request_headers on;
这一参数。
例如:
location /
include /etc/nginx/uwsgi_params; # the uwsgi_params file you installed
uwsgi_pass_request_headers on;
uwsgi_pass django;
【讨论】:
【参考方案5】:上面的答案足以让我们找出路。但是我们仍然需要知道一个令人讨厌的点。是的,这很烦人。
proxy_set_header X_FORWARDED_FOR # oops it never works. 1.16.1 on centos7
proxy_set_header X-FORWARDED-FOR # this will do the job
所以你明白了。下划线永远不会出现在自定义变量名称中。请改用连字符。
也许Nginx
在某些语法情况下使用下划线。有人指出官方参考将不胜感激。
【讨论】:
【参考方案6】:这取决于自定义标头的命名方式。我的格式是“SomethingLike.this”,它包含一个点。无法重命名请求中的标头,因为它不是我们的代码。所以写这个是行不通的:
proxy_set_header SomethingLike.this $http_somethinglike.this;
proxy_pass_header SomethingLike.this;
这也行不通:
underscores_in_headers on;
因为我需要不存在的dots_in_headers
指令。
但我发现我可以通过添加以下内容来传递所有标题:
ignore_invalid_headers off;
传递所有header可能不安全,请谨慎使用。
【讨论】:
以上是关于缺少 django、nginx 和 gunicorn 的自定义标头的主要内容,如果未能解决你的问题,请参考以下文章
数字海洋 NGINX 和 gunicorn 上的 CORS 标头访问控制缺少 django
缺少 django、nginx 和 gunicorn 的自定义标头
Flask + Nginx + Gunicorn + Gevent部署