【问题标题】:Missing custom header with django, nginx and gunicorn缺少 django、nginx 和 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_

标签: django configuration http-headers nginx gunicorn


【解决方案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 部分,以了解如何传递您需要的标头。

您可以在此处找到文档:

最后一个条目似乎表明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可能不安全,请谨慎使用。

          【讨论】:

            猜你喜欢
            • 2018-09-12
            • 2015-09-25
            • 2020-02-21
            • 2016-04-03
            • 1970-01-01
            • 2016-01-20
            • 2021-09-27
            • 2015-04-17
            • 2016-06-21
            相关资源
            最近更新 更多