Nginx别名因try\u文件$uri别名错误而中断
我有一个版本化的Symfony API实例,我希望以以下方式配置该实例:Nginx别名因try\u文件$uri别名错误而中断,nginx,nginx-config,Nginx,Nginx Config,我有一个版本化的Symfony API实例,我希望以以下方式配置该实例: api.com/api/v1->/srv/api-v1/public/index.php api.com/api/v2->/srv/api-v2/public/index.php 我尝试使用nginx位置和别名来实现这一点,因为在默认设置为index.php之前,我们使用try\u files()检查实际文件 问题 似乎有一个函数使用别名和try\u文件来中断$uri变量 我怎样才能绕过这个bug来达到我想要的结果 n
- api.com/api/v1->/srv/api-v1/public/index.php
- api.com/api/v2->/srv/api-v2/public/index.php
index.php
之前,我们使用try\u files()检查实际文件
问题
似乎有一个函数使用别名和try\u文件
来中断$uri
变量
我怎样才能绕过这个bug来达到我想要的结果
nginx conf
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;
}
}
试图修复
接下来,我创建了以下配置文件,虽然可以工作,但会生成一个巨大的配置文件,这并不理想:
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;
}
}
当alias
指令与try\u files
指令一起使用时,可以使用另一种变通方法(请参见答案中的示例)。你能试试下面的配置吗
服务器{
听443http2;
听[:]:443 http2;
服务器名称api.com;
root/srv/default/public/;#无版本时的默认根目录
位置~^/api/v1(?/*){
别名/srv/api-v1/public;
try_files$v1route/api/v1/index.php$is_args$args;
位置~^/api/v1/index\.php${
内部的;
包括/etc/nginx/fastcgi.conf;
fastcgi_param SCRIPT_FILENAME/srv/api-v1/public/index.php;
fastcgi_读取超时300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
位置~^/api/v2(?/*){
别名/srv/api-v2/public;
try_文件$v2route/api/v2/index.php$is_args$args;
位置~^/api/v2/index\.php${
内部的;
包括/etc/nginx/fastcgi.conf;
fastcgi_param SCRIPT_FILENAME/srv/api-v2/public/index.php;
fastcgi_读取超时300;
fastcgi_pass unix:/run/php-fpm-php7.2.socket;
}
}
}
临时更新(将随说明扩展)
OP提出了另一个问题:
Symfony期望的默认值有一个小问题。以下三个服务器变量$\u server['DOCUMENT\u URI']
,$\u server['SCRIPT\u NAME']
和$\u server['PHP\u SELF']
equal/api/v1/index.PHP
但是默认的Symfony nginx生成/index.PHP
,有没有办法在上面进行调整
我不认为这是Symfony行为不正确的原因。虽然这些变量当然可以调整,但最可能的原因是不正确的$\u SERVER['REQUEST\u URI']
值。使用上面的配置,它将等于/api/v1/some/path
,但Symfony最有可能期望的是/some/path
。以下是您可以尝试覆盖该变量的配置:
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;
}
}
}
我认为这应该可以解决您的问题,但是如果您真的想调整$\u服务器['DOCUMENT\u URI']
,$\u服务器['SCRIPT\u NAME']
和$\u服务器['PHP\u SELF']
,您可以在嵌套位置添加两行额外的代码:
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
要防止$\u服务器['REQUEST\u URI']
变量为空字符串,可以使用以下选项:
将请求从/api/v1
或/api/v2
重定向到/api/v1/
或/api/v2/
(对我来说似乎是最好的):
在确切的/api/v1
或/api/v2
请求中明确添加尾部斜杠:
map $request_uri $api_ver {
~^/api/v([12])/? $1;
}
map $request_uri $api_route {
~^/api/v[12](?:/([^?]*))?(?:$|\?) /$1;
}
server {
...
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;
}
}
}
如果$\u服务器['REQUEST\u URI']
变量值前面应该有/api
字符串,您可以尝试fastcgi\u参数REQUEST\u URI/api$api\u route$is\u args$args
而不是fastcgi\u-param-REQUEST\u-URI$api\u-route$is\u-args$args代码>
如果要调整$\u服务器['DOCUMENT\u URI']
,$\u服务器['SCRIPT\u NAME']
和$\u服务器['PHP\u SELF']
变量,请添加
fastcgi_param DOCUMENT_URI /index.php;
fastcgi_param SCRIPT_NAME /index.php;
行到嵌套位置。在“hacky fix”中,您缺少代理传递
指令的尾部/
。
以下是一个repo,可以轻松测试您的实现:
查看是否需要有关尾随斜杠的更多信息。如果您对“hacky fix”没有问题,可以将其弄得更干净一些。只需将重复配置放入其他文件中。然后可以使用include
指令导入另一个文件
/etc/nginx/some\u other\u文件:
您可以将if
和$request\u filename
与别名一起使用,以避免使用try\u文件
。您还需要为PHP URI使用嵌套位置。请参阅。注意在位置上下文中使用if。请参阅测试,到目前为止,这似乎如预期的那样工作,是一个更简单的解决方案。非常感谢。是的,大多数变量都是通过/etc/nginx/fastcgi.conf
(基于Debian)或/etc/nginx/fastcgi_params
(基于RHEL)文件定义为默认值的。您可以重新定义它们(仅在包含文件fastcgi.conf
之后,请参阅答案以获取更多解释)。对我来说,PHP应用程序的行为可能依赖于请求URI
和文档URI
之外的任何其他变量,这似乎很奇怪。我很快会对答案进行更新,但现在没有时间。我昨天开始写一个非常大的答案,但系统崩溃:(您要求的是一个小的调整,您需要在include/etc/nginx/fastcgi.conf;
行之后的两个嵌套位置添加fastcgi\u-param-DOCUMENT\u-URI/index.php;
和fastcgi-param-SCRIPT\u-NAME/index.php;
行,但我担心您的问题来自REQUEST\u-URI的值不正确。)代码>变量(您需要剥离/api/vN
substri
fastcgi_param DOCUMENT_URI /index.php;
fastcgi_param SCRIPT_NAME /index.php;
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;
}
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;
}