缺少 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 的自定义标头

Django测试抱怨缺少表问题,怎么解决

Flask + Nginx + Gunicorn + Gevent部署

Docker + Django + Vue.js + Webpack 如何正确配置 nginx?

Gunicorn`无法连接到('ind',8000)` - Django,EC2,Nginx