首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >try_files $uri别名错误导致Nginx别名中断

try_files $uri别名错误导致Nginx别名中断
EN

Stack Overflow用户
提问于 2020-12-01 15:30:49
回答 3查看 1.6K关注 0票数 1

我有一个版本化的Symfony API实例,我想以以下方式配置它:

  • api.com/api/v1 -> /srv/api-v1/public/index.php
  • api.com/api/v2 -> /srv/api-v2/public/index.php

我尝试使用nginx位置和别名来处理这个问题,因为我们使用try_files (按建议)在默认为index.php之前检查实际文件。

问题

似乎有一个已知的nginx虫可以用aliastry_files来打破$uri变量。

我怎样才能绕过这个bug来达到我想要的结果呢?

nginx conf

代码语言:javascript
复制
server {
    listen 443 http2;
    listen [::]:443 http2;
    server_name api.com;
    root /srv/default/public/; # default root when no version
 
    location /api/v1 {
        alias /srv/api-v1/public/;
        try_files $uri /index.php$is_args$args;
    }

    location /api/v2 {
        alias /srv/api-v2/public/;
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        include /etc/nginx/fastcgi.conf;
        fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        internal;
        fastcgi_read_timeout 300;
    }
}

尝试修复

通过这种无趣的解决办法,我创建了以下功能,但是生成了一个巨大的配置文件,这并不理想:

代码语言:javascript
复制
upstream v1 {
    server 127.0.0.1;
}
upstream v2 {
    server 127.0.0.1;
}
server {
    listen 443 http2;
    listen [::]:443 http2;
    server_name api.com;
 
    location /api/v1 {
        proxy_pass http://v1;
    }

    location /api/v2 {
        proxy_pass http://v2;
    }
}
server {
    server_name v1;
    root /srv/api-v1/public/;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        include /etc/nginx/fastcgi.conf;
        fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        internal;
    }
}
server {
    server_name v2;
    root /srv/api-v2/public/;

    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        include /etc/nginx/fastcgi.conf;
        fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        internal;
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-12-03 11:06:07

还有另一种解决方法,当alias指令与try_files指令一起使用时,可以使用这种方法(示例请参见答案)。你能试试下面的配置吗?

代码语言:javascript
复制
server {
    listen 443 http2;
    listen [::]:443 http2;
    server_name api.com;
    root /srv/default/public/; # default root when no version
 
    location ~ ^/api/v1(?<v1route>/.*)? {
        alias /srv/api-v1/public;
        try_files $v1route /api/v1/index.php$is_args$args;
        location ~ ^/api/v1/index\.php$ {
            internal;
            include /etc/nginx/fastcgi.conf;
            fastcgi_param SCRIPT_FILENAME /srv/api-v1/public/index.php;
            fastcgi_read_timeout 300;
            fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        }
    }

    location ~ ^/api/v2(?<v2route>/.*)? {
        alias /srv/api-v2/public;
        try_files $v2route /api/v2/index.php$is_args$args;
        location ~ ^/api/v2/index\.php$ {
            internal;
            include /etc/nginx/fastcgi.conf;
            fastcgi_param SCRIPT_FILENAME /srv/api-v2/public/index.php;
            fastcgi_read_timeout 300;
            fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        }
    }
}

临时更新(随解释展开)

执行部分提出了另一个问题:

Symfony期望的缺省值有一个小问题。以下三个服务器变量$_SERVER['DOCUMENT_URI']$_SERVER['SCRIPT_NAME']$_SERVER['PHP_SELF']等于/api/v1/index.php,但是默认的Symfony nginx生成/index.php,在上面有什么方法来调整吗?

我不认为这是不正确的Symfony行为的原因。虽然这个变量当然可以调整,但最可能的原因是$_SERVER['REQUEST_URI']值不正确。有了上面的配置,它将等于/api/v1/some/path,但很可能Symfony只期望使用/some/path。下面是您可以尝试覆盖该变量的配置:

代码语言:javascript
复制
map $request_uri $api_ver {
    ~^/api/v([12])/?  $1;
}
map $request_uri $api_route {
    ~^/api/v[12](/[^?]*)?(?:$|\?)  $1;
}
server {
    listen 443 http2;
    listen [::]:443 http2;
    server_name api.com;
    root /srv/default/public; # default root when no version

    location ~ ^/api/v[12]/? {
        alias /srv/api-v$api_ver/public;
        try_files $api_route /api/v$api_ver/index.php$is_args$args;
        location ~ ^/api/v[12]/index\.php$ {
            internal;
            include /etc/nginx/fastcgi.conf;
            fastcgi_param REQUEST_URI $api_route$is_args$args;
            fastcgi_param SCRIPT_FILENAME /srv/api-v$api_ver/public/index.php;
            fastcgi_read_timeout 300;
            fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        }
    }
}

我认为这应该可以解决您的问题,但是如果确实希望调整$_SERVER['DOCUMENT_URI']$_SERVER['SCRIPT_NAME']$_SERVER['PHP_SELF'],您可以在嵌套位置中增加两行:

代码语言:javascript
复制
        location ~ ^/api/v[12]/index\.php$ {
            internal;
            include /etc/nginx/fastcgi.conf;
            fastcgi_param REQUEST_URI $api_route$is_args$args;
            fastcgi_param DOCUMENT_URI /index.php;
            fastcgi_param SCRIPT_NAME /index.php;
            fastcgi_param SCRIPT_FILENAME /srv/api-v$api_ver/public/index.php;
            fastcgi_read_timeout 300;
            fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        }

但我不认为这是正确的Symfony行为所必需的。

更新2

为了防止$_SERVER['REQUEST_URI']变量成为空字符串,您有以下选项:

  1. 将请求从/api/v1/api/v2重定向到/api/v1//api/v2/ (似乎对我最好): 映射$request_uri $api_ver { ~^/api/v(12)/ $1;}映射$request_uri $api_route {~^/api/v12(?) $1;}服务器{.位置~ ^/api/v12$ {返回301 args$args;} location ~ ^/api/v12/ {别名/srv/api-v$api_ver/public;try_files $api_route /api/v$api_ver/index.php$is_args$args;location ~ ^/api/v12/index.php$ { include;try_files/etc/nginx/快速cgi.conf;fastcgi_param REQUEST_URI $api_route$is_args$args;fastcgi_param SCRIPT_FILENAME /srv/api$api_ver/public/index.php;fastcgi_read_timeout 300;fastcgi_pass unix:/run/php7.2.Socket;}}
  2. 显式地将尾随斜杠添加到确切的/api/v1/api/v2请求: 映射$request_uri $api_ver { ~^/api/v(12)/?$1;}映射$request_uri $api_route {~^/api/v12?(?:$$\\?) /$1;}服务器{.位置~ ^/api/v12/?{别名/srv/api-v$api_ver/public;try_files $api_route /api/v$api_ver/index.php$is_args$args;location ~ ^/api/v12/index.php$ { include;包括/etc/nginx/快速cgi.conf;fastcgi_param REQUEST_URI $api_route$is_args$args;fastcgi_param SCRIPT_FILENAME /srv/api$api_ver/public/index.php;fastcgi_read_timeout 300;fastcgi_pass unix:/run/php7.2.Socket;}}

如果$_SERVER['REQUEST_URI']变量值应加上/api字符串,则可以尝试使用fastcgi_param REQUEST_URI /api$api_route$is_args$args;而不是fastcgi_param REQUEST_URI $api_route$is_args$args;

如果要调整$_SERVER['DOCUMENT_URI']$_SERVER['SCRIPT_NAME']$_SERVER['PHP_SELF']变量,请添加

代码语言:javascript
复制
fastcgi_param DOCUMENT_URI /index.php;
fastcgi_param SCRIPT_NAME /index.php;

嵌套位置的行。

票数 1
EN

Stack Overflow用户

发布于 2020-12-03 16:07:19

在"hacky修复“中,您缺少了指向您的/指令的尾部proxy_pass。下面是一个很容易测试您的实现的回购:https://github.com/MelwinKfr/nginx-workaround97

如果您想要更多关于尾随斜杠的信息,请参见这条线

票数 0
EN

Stack Overflow用户

发布于 2021-01-15 08:38:41

如果你对“黑客修复”没意见,你可以让它变得更干净一些。只需将重复配置放入其他文件即可。然后可以使用include指令导入另一个文件。

/etc/nginx/_file:

代码语言:javascript
复制
    location / {
        try_files $uri /index.php$is_args$args;
    }

    location ~ ^/index\.php(/|$) {
        include /etc/nginx/fastcgi.conf;
        fastcgi_pass unix:/run/php-fpm-php7.2.socket;
        fastcgi_split_path_info ^(.+?\.php)(/.*)$;
        internal;
    }
代码语言:javascript
复制
upstream v1 {
    server 127.0.0.1;
}
upstream v2 {
    server 127.0.0.1;
}
server {
    listen 443 http2;
    listen [::]:443 http2;
    server_name api.com;
 
    location /api/v1 {
        proxy_pass http://v1;
    }

    location /api/v2 {
        proxy_pass http://v2;
    }
}
server {
    server_name v1;
    root /srv/api-v1/public/;
    include some_other_file;
}
server {
    server_name v2;
    root /srv/api-v2/public/;
    include some_other_file;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65093486

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档