uwsgi_pass不转发SCRIPT_NAME标头 [英] uwsgi_pass does not forward SCRIPT_NAME header

查看:107
本文介绍了uwsgi_pass不转发SCRIPT_NAME标头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从主域的某些子文件夹中提供我的Web应用程序(基于Django/wsgi). 我将docker用于我的应用程序和静态文件,因此我在服务器上使用了主要的nginx作为反向代理,在"nginx"容器中使用了另一个nginx,用于将我的应用程序的内容和uWSGI路由到第二个容器中,该容器用于提供实际的Django数据

I'm trying to make my web app (Django/wsgi-based) available from some subfolder of the main domain. I'm using docker for my app, and static files, so I have main nginx on my server as reverse proxy, another nginx in "nginx" container which routes the stuff for my app and uWSGI in the second container which serves actual Django data

并且我希望我的应用可以以myserver.com/mytool的形式在外部使用,与此同时,我不想在应用中的任何地方对mytool进行硬编码.通常SCRIPT_NAME标头用于这种类型的东西,因此这是主机上的nginx配置:

And I want my app to be available externally as myserver.com/mytool, in the same time I do not want to hardcode mytool anywhere in my app. Usually SCRIPT_NAME header is used for this type of stuff, so here is nginx configuration on the host:

server {
  listen 80; # Just for sake of simplicity, of course in production it's 443 with SSL
  location /mytool/ {
    proxy_pass http://127.0.0.1:8000/;
    include proxy_params;
    proxy_set_header SCRIPT_NAME /mytool;  # <--- Here I define my header which backend should use
  }
}

然后在我的docker-compose中,我为nginx公开了8000:80,这是内部nginx配置:

Then in my docker-compose I expose 8000:80 for nginx and here is internal nginx configuration:

server {
  listen 80;
  location / {
    include uwsgi_params;
    uwsgi_pass web:3031;
  }
}

通过这种配置,我希望我的Django应用接收到SCRIPT_NAME标头,但显然没有.

With this configuration I would expect that my Django app receives SCRIPT_NAME header, but apparently it does not.

同时,如果我定义自定义标头(如proxy_set_header X-something something;),则此标头将正确转发,并且可以从Django中看到它.

In the same time if I define custom headers like proxy_set_header X-something something; then this gets forwarded correctly and I can see it from Django.

我应该如何传递SCRIPT_NAME以避免在代码中使用路径硬编码?

How should I pass SCRIPT_NAME to avoid path hardcode in my code?

推荐答案

这里有两个问题.

首先,nginx将包含下划线的标头视为无效,因此SCRIPT_NAME标头不会被容器中的nginx接受,因为从nginx角度来看,它是无效的.幸运的是,nginx指令 underscores_in_headers 在这里可以提供帮助.

First is that nginx considers headers which contain underscores as invalid, so SCRIPT_NAME header is not being accepted by nginx in the container because it's invalid from nginx point of view. Luckily, nginx directive underscores_in_headers is here to help.

只需在Docker 内的nginx server部分中添加underscores_in_headers on;(而不是在主机中).

Just add underscores_in_headers on; to server section of nginx inside Docker (not to the host one).

完成此操作后,还有另一个问题-nginx在其名称前面转发在HTTP之前的标头.因此,现在从Django端您将看到HTTP_SCRIPT_NAME而不是SCRIPT_NAME.但是,再次幸运的是,可以再次在Docker内部的nginx中使用uwsgi_param SCRIPT_NAME $http_script_name;行来轻松修复它.

When this is done here is yet another issue - nginx forwards header prepending HTTP in front of its name. So now from Django side you will see HTTP_SCRIPT_NAME instead of SCRIPT_NAME. But again, luckily for us, it can be easily fixed by using uwsgi_param SCRIPT_NAME $http_script_name; line in nginx inside Docker again.

因此,Docker内部的最终nginx配置应如下所示:

Thus, final nginx config inside Docker should look like:

server {
  underscores_in_headers on;  # <---- (1)
  listen 80;
  location / {
    include uwsgi_params;
    uwsgi_pass web:3031;
    uwsgi_param SCRIPT_NAME $http_script_name; # <--- (2)        
  }
}

这篇关于uwsgi_pass不转发SCRIPT_NAME标头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆