【问题标题】:Location block root overwritten by server root definition on nginx位置块根被 nginx 上的服务器根定义覆盖
【发布时间】:2020-12-25 07:45:30
【问题描述】:

我已经与这个“问题”斗争了几天,无法弄清楚我的 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 文件) 对于与该位置不匹配的任何其他文件,它应该与根位置匹配。

这是“主”日志模板的配置:

        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" ';

如果我要求,使用此配置

domain.com/flowers.json

它返回位于服务器文档根目录的 index.php

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"

如果我尝试使用存在的 domain.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 文件。但是没有用

我在 location json 块上注释了 try_files 指令

  location ~ \.json$ {
    add_header location micro;
    root /data/micro/public/;
    #try_files  /index.html /index.php;
    location ~ \.php$ {
        [...]
    }
  }

请注意,document_root 保持不变,正如我之前定义的那样。

现在,如果我尝试

domain.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"

domain.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。

哦,差点忘了:请注意,我正在使用标题来检查哪个位置块匹配;在前两种情况下,匹配的块是 PHP 位置;在最后两种情况下,它与 json 位置匹配。

我已经检查了 nGinx 文档中的 Pitfalls and Common Mistakes 以及 official ngx_http_core_module documentation;他们有帮助,但还不够。

有人知道我做错了什么吗? 非常感谢

【问题讨论】:

    标签: php nginx configuration config


    【解决方案1】:

    当您使用try_files 时,当前选择的位置会切换到另一个位置。

    AFAIK,在使用try_files 跳转/切换上下文时不会继承指令(或者至少是这样,除非跳转最终从父位置到嵌套位置)。

    NGINX 最终将使用一个最终位置来满足请求。 哪些 指令“适用于”为请求提供服务是在该位置指定的指令以及从上层继承的任何指令(而不是从跳转的指令)。即便如此,并非所有内容都继承自父上下文(特定指令之间差异很大)。

    这个想法是 json 位置匹配任何 json 请求,如果文件不存在,请尝试使用 index.php(它将构建该 json 文件)。

    但是在你的代码中你有:

    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;
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-18
      • 2023-03-23
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      • 2014-07-21
      • 2023-03-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多