位置块根被 nginx 上的服务器根定义覆盖
Location block root overwritten by server root definition on nginx
我已经和这个 'issue' 斗争了几天,无法弄清楚我的 nGinx 服务器内部发生了什么。
这是几天来噩梦般的服务器配置
server {
listen 80 ;
listen [::]:80;
server_name domain.com *. domain.com;
root /data;
access_log /var/log/nginx/access.log main;
location ~ \.json$ {
add_header location micro;
root /data/micro/public/;
try_files /index.html /index.php;
location ~ \.php$ {
root /data/micro/public/;
try_files /index.php?$request_uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/micro/public/index.php;
include fastcgi_params;
}
}
location ~ \.php$ {
add_header location php;
try_files $uri =404;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location / {
try_files $uri $uri/ /index.php;
add_header location general;
}
}
想法是 json 位置匹配任何 json 请求,如果文件不存在,请尝试使用 index.php(这将构建 json文件)
对于与该位置不匹配的任何其他文件,它应该与根位置匹配。
这是 'main' 日志模板的配置:
log_format main 'time_local="$time_local" site="$server_name" '
'status="$status" uri_query="$query_string" uri_path="$uri" '
'request_filename="$request_filename" request_uri="$request_uri" '
'uri="$uri" realpath_root="$realpath_root" document_root="$document_root" ';
有了这个配置,如果我要求
域名.com/flowers.json
它returns位于服务器根目录的index.php文件root
time_local="06/Sep/2020:18:51:56 +0000" site="domain.com" status="200" uri_query="" uri_path="/index.php" request_filename="/data/index.php" request_uri="/flowers.json" uri="/index.php" realpath_root="/data" document_root="/data"
如果我尝试使用存在的域。com/test.json,我得到相同的结果
time_local="06/Sep/2020:19:02:40 +0000" site="domain.com" status="200" uri_query="" uri_path="/index.php" request_filename="/data/index.php" request_uri="/test.json" uri="/index.php" realpath_root="/data" document_root="/data"
在第一种情况下,我希望从位置文档根指令中得到 index.php,即 /data/micro/public;在第二种情况下,我希望从同一位置获得 test.json 文件。但是没用
我在 json 块
位置评论了 try_files 指令
location ~ \.json$ {
add_header location micro;
root /data/micro/public/;
#try_files /index.html /index.php;
location ~ \.php$ {
[...]
}
}
请注意,document_root 保持不变,正如我之前定义的那样。
现在,如果我尝试
域名.com/flowers.json
我明白了
time_local="06/Sep/2020:19:06:26 +0000" site="domain.com" status="404" uri_query="-" uri_path="/sellers.json" request_filename="/data/micro_sellers/public/sellers.json" request_uri="/sellers.json" uri="/sellers.json" realpath_root="/data/micro_sellers/public" document_root="/data/micro_sellers/public"
并与
域名.com/test.json
我明白了
time_local="06/Sep/2020:19:06:34 +0000" site="tappx.com" status="200" uri_query="-" uri_path="/test.json" request_filename="/data/micro_sellers/public/test.json" request_uri="/test.json" uri="/test.json" realpath_root="/data/micro_sellers/public" document_root="/data/micro_sellers/public"
这是我在第一个配置中所期望的,但它一直失败,因为指令 try_files 未启用并且在 json 文件启用时无法尝试使用 index.php不存在。
哦,差点忘了:请注意,我正在使用header来检查哪个位置块匹配;在前两种情况下,匹配的块是 PHP 位置;在最后两种情况下,它与 json 位置匹配。
我检查过Pitfalls and Common Mistakes from the nGinx documentation as well as the official ngx_http_core_module documentation;他们提供了帮助,但还不够。
有人知道我做错了什么吗?
非常感谢
当您使用 try_files
时,当前选择的位置会切换到另一个位置。
AFAIK,当 jumping/switching 上下文使用 try_files
时,将不会继承指令(或者至少如此,除非跳转从父位置到嵌套位置结束)。
NGINX 最终将使用一个最终位置来满足请求。 哪些 指令“应用于”为请求提供服务是在该位置指定的指令以及从上层继承的指令(不是从跳转的指令)。即便如此,也并非所有内容都从父上下文继承(特定指令之间差异很大)。
The idea is the json location matches any json request and, if the file doesn't exist, try with index.php (which will build that json file).
但是在你的代码中你有:
try_files /index.html /index.php;
注意这条规则以了解 try_files
的工作原理:检查第一个参数是否存在,如果存在,则 URI 更改其路径和位置匹配重新启动。 last 参数的唯一不同之处在于它从不检查是否存在,并且当所有先前的参数都不作为文件存在时 URI 切换到它。
所以当 .json
文件不存在时,NGINX 将简单地检查文件 /index.html
是否不存在(据我所知它不存在),然后最终跳转到 /index.php
.
位置搜索重新开始。而且它不会按照您的期望跳转到嵌套位置。只是因为 URL 不再匹配 .json
扩展名。因此它将落在服务器级别的 location ~ \.php$ {
中,而不是嵌套级别。该位置将继承 root /data;
.
所以总而言之,这种嵌套永远没有意义:
location ~ \.json$ {
location ~ \.php$ {
...
因为不可能有一个文件名同时以 .json
和 .php
扩展名结尾:-)
对于“如果不存在则生成”方法,您可能想要以更明确的方式做的是使用命名位置。
location ~ \.json$ {
root /data/micro/public/;
try_files $uri @json_gen;
}
location @json_gen {
root /data/micro/public/;
# do not include any try_files here for less surprises :)
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}
我已经和这个 'issue' 斗争了几天,无法弄清楚我的 nGinx 服务器内部发生了什么。
这是几天来噩梦般的服务器配置
server {
listen 80 ;
listen [::]:80;
server_name domain.com *. domain.com;
root /data;
access_log /var/log/nginx/access.log main;
location ~ \.json$ {
add_header location micro;
root /data/micro/public/;
try_files /index.html /index.php;
location ~ \.php$ {
root /data/micro/public/;
try_files /index.php?$request_uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/micro/public/index.php;
include fastcgi_params;
}
}
location ~ \.php$ {
add_header location php;
try_files $uri =404;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location / {
try_files $uri $uri/ /index.php;
add_header location general;
}
}
想法是 json 位置匹配任何 json 请求,如果文件不存在,请尝试使用 index.php(这将构建 json文件) 对于与该位置不匹配的任何其他文件,它应该与根位置匹配。
这是 'main' 日志模板的配置:
log_format main 'time_local="$time_local" site="$server_name" '
'status="$status" uri_query="$query_string" uri_path="$uri" '
'request_filename="$request_filename" request_uri="$request_uri" '
'uri="$uri" realpath_root="$realpath_root" document_root="$document_root" ';
有了这个配置,如果我要求
域名.com/flowers.json
它returns位于服务器根目录的index.php文件root
time_local="06/Sep/2020:18:51:56 +0000" site="domain.com" status="200" uri_query="" uri_path="/index.php" request_filename="/data/index.php" request_uri="/flowers.json" uri="/index.php" realpath_root="/data" document_root="/data"
如果我尝试使用存在的域。com/test.json,我得到相同的结果
time_local="06/Sep/2020:19:02:40 +0000" site="domain.com" status="200" uri_query="" uri_path="/index.php" request_filename="/data/index.php" request_uri="/test.json" uri="/index.php" realpath_root="/data" document_root="/data"
在第一种情况下,我希望从位置文档根指令中得到 index.php,即 /data/micro/public;在第二种情况下,我希望从同一位置获得 test.json 文件。但是没用
我在 json 块
位置评论了 try_files 指令 location ~ \.json$ {
add_header location micro;
root /data/micro/public/;
#try_files /index.html /index.php;
location ~ \.php$ {
[...]
}
}
请注意,document_root 保持不变,正如我之前定义的那样。
现在,如果我尝试
域名.com/flowers.json
我明白了
time_local="06/Sep/2020:19:06:26 +0000" site="domain.com" status="404" uri_query="-" uri_path="/sellers.json" request_filename="/data/micro_sellers/public/sellers.json" request_uri="/sellers.json" uri="/sellers.json" realpath_root="/data/micro_sellers/public" document_root="/data/micro_sellers/public"
并与
域名.com/test.json
我明白了
time_local="06/Sep/2020:19:06:34 +0000" site="tappx.com" status="200" uri_query="-" uri_path="/test.json" request_filename="/data/micro_sellers/public/test.json" request_uri="/test.json" uri="/test.json" realpath_root="/data/micro_sellers/public" document_root="/data/micro_sellers/public"
这是我在第一个配置中所期望的,但它一直失败,因为指令 try_files 未启用并且在 json 文件启用时无法尝试使用 index.php不存在。
哦,差点忘了:请注意,我正在使用header来检查哪个位置块匹配;在前两种情况下,匹配的块是 PHP 位置;在最后两种情况下,它与 json 位置匹配。
我检查过Pitfalls and Common Mistakes from the nGinx documentation as well as the official ngx_http_core_module documentation;他们提供了帮助,但还不够。
有人知道我做错了什么吗? 非常感谢
当您使用 try_files
时,当前选择的位置会切换到另一个位置。
AFAIK,当 jumping/switching 上下文使用 try_files
时,将不会继承指令(或者至少如此,除非跳转从父位置到嵌套位置结束)。
NGINX 最终将使用一个最终位置来满足请求。 哪些 指令“应用于”为请求提供服务是在该位置指定的指令以及从上层继承的指令(不是从跳转的指令)。即便如此,也并非所有内容都从父上下文继承(特定指令之间差异很大)。
The idea is the json location matches any json request and, if the file doesn't exist, try with index.php (which will build that json file).
但是在你的代码中你有:
try_files /index.html /index.php;
注意这条规则以了解 try_files
的工作原理:检查第一个参数是否存在,如果存在,则 URI 更改其路径和位置匹配重新启动。 last 参数的唯一不同之处在于它从不检查是否存在,并且当所有先前的参数都不作为文件存在时 URI 切换到它。
所以当 .json
文件不存在时,NGINX 将简单地检查文件 /index.html
是否不存在(据我所知它不存在),然后最终跳转到 /index.php
.
位置搜索重新开始。而且它不会按照您的期望跳转到嵌套位置。只是因为 URL 不再匹配 .json
扩展名。因此它将落在服务器级别的 location ~ \.php$ {
中,而不是嵌套级别。该位置将继承 root /data;
.
所以总而言之,这种嵌套永远没有意义:
location ~ \.json$ {
location ~ \.php$ {
...
因为不可能有一个文件名同时以 .json
和 .php
扩展名结尾:-)
对于“如果不存在则生成”方法,您可能想要以更明确的方式做的是使用命名位置。
location ~ \.json$ {
root /data/micro/public/;
try_files $uri @json_gen;
}
location @json_gen {
root /data/micro/public/;
# do not include any try_files here for less surprises :)
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php7.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
include fastcgi_params;
}