首页 > 解决方案 > 在 NGINX 位置块中使用 try_files 并重写,带有默认的前端控制器文件

问题描述

我正在从旧框架迁移到 php 中的新框架。旧框架对每个 URL 都有一个登录页面,例如:

  1. test.com/page1将被路由到public_directory/page1.php

  2. test.com/another_page将被路由到public_directory/another_page.php

  3. 等等

以下块用于这些请求:

location / { 
    limit_req zone=globallimit burst=20 nodelay;
    try_files $uri $uri/ @php; 
}

location @php {         
    rewrite ^(/[^/]+)$ $1.php last;
    rewrite ^(/[^/]+)/(.*)$ $1.php?q=$2 last;
}

新框架使用前端控制器,每个请求都需要定向到public_directory/front_controller.php. 当我们迁移时,我们正在删除旧的登录文件,这是我们可以识别哪些页面使用新框架的方式。

我认为会起作用的是,在@php块之后,将默认参数添加到front_controller.php

location / { 
    limit_req zone=globallimit burst=20 nodelay;
    try_files $uri $uri/ @php /front_controller.php?$arg; 
}

location @php {         
    rewrite ^(/[^/]+)$ $1.php last;
    rewrite ^(/[^/]+)/(.*)$ $1.php?q=$2 last;
}

如果@php 重写块不匹配文件,那么它应该默认为/front_controller.php?arg; 但是,我发现现在@php 被忽略,nginx而是直接转到front_controller.php。我哪里错了,为什么@php重写现在被忽略了?

标签: nginxnginx-config

解决方案


try_files指令需要一个文件列表,后跟 URI / 命名位置 / HTTP 错误代码,如果列表中的文件都不存在,则将使用该列表。假设您的站点根目录是/home/user/www并且您的请求是http://example.com/some/path此配置,请检查以下文件/目录是否存在:

  1. /home/user/www/some/path文件,如果找到该文件,它的内容将在响应正文中返回。
  2. /home/user/www/some/path/目录,如果该目录存在,将检查该index指令定义的所有可能的索引文件,将使用第一个找到的文件。如果在此目录中没有找到索引文件,则 nginx 如果有则返回目录内容,autoindex on;否则返回 HTTP 403 Forbidden。
  3. /home/user/www@php文件。显然,找不到该文件。

如果这些检查都没有成功,nginx 将遵循定义为最后一个参数的 URI(或命名位置)(/front_controller.php?$arg在这种情况下)。

你可以做的是尝试类似的东西

location ~ ^(/[^/]+)$ {
    try_files $1.php /front_controller.php?$arg;
}
location ~ ^(?<script>/[^/]+)/(?<param>.*)$ {
    rewrite ^ $script?q=$param last;
}

但是我不明白$arg变量应该来自哪里。也许你的意思是$is_args$args

更新

我错了,您可以使用指令检查 php 脚本是否存在try_files,但该脚本不会传递到您的 php 处理程序位置块。你的任务引起了我的兴趣,最后我得到了一些工作:

# backup original args
set $original_args $args;
if ($uri ~ "^(/[^/]+)(?:/(.*))?$") {
    set $script $1.php;
    set $param $2;
}
if ($param) {
    set $args "q=$param";
}
location / { 
    limit_req zone=globallimit burst=20 nodelay;
    try_files $uri $uri/ @php; 
}
location @php {
    if ( !-f $document_root$script ) {
        # old landing php file is absent, restore original args and rewrite URI to /front_controller.php
        set $args $original_args;
        set $script /front_controller.php;
    }
    rewrite ^ $script last;
}

推荐阅读