解决 Nginx 报 File not found.

我刚开始接触到互联网时大都用的是Apache(用虚拟主机搭博客),后来工作了发现公司都是用的Nginx,Nginx的牛逼之处就不bb了,显而易见。

后来使用Nginx搭建博客,配置伪静态(PATH_INFO)时,如果请求的是 /xxx.php 就会报 File not found. 如果是 /xxxx 就正常,带了php结尾就不行。这个问题困扰了我很长时间,一直不得解。

这次重装系统,在网上找资料加上反复动手实验,终于解决了,正确配置如下。

if (!-e $request_filename) {
    rewrite ^(.*)$ /index.php$1 last;
    break;
}

location ~ \.php(.*)$ {
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_split_path_info  ^((?U).+\.php)(.+)$;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    fastcgi_param  PATH_INFO $fastcgi_path_info;
    include        fastcgi_params;
}

PS: if 的优先级比 location 高,放 location 前后面都行,大致逻辑是判断请求的 path 既不是文件也不是目录,就重写到 /index.php/xxx 去解析。
fastcgi_split_path_info 的正则主要是匹配2个参数,一个是 $fastcgi_script_name 执行文件名, $fastcgi_path_info 匹配 PATH_INFO。
关于正则网上有 ^(.+\.php)(.+)$ ^(.+\.php)(/?.+)$ ^((?U).+\.php)(.+)$ 的写法,经过测试带 (?U) 要正确些(不带也不报错)。
如URL /a.php/cccc,如果带了 (?U) 那么执行文件名则拿到 /index.php,PATH_INFO 拿到的是/a.php/cccc (应当请求的 PATH 为 PATH_INFO 才对,所以这里要正确些)。否则执行文件名拿到的是 /index.php/a.php,PATH_INFO 拿到的是 /cccc,建议动手实验一下就清楚了(配置上方规则,不带 (?U) ,新建 index.php,内容为 <?php var_dump($_SERVER); 请求 /a.php/ccc 看 $_SERVER 打印的 PATH_INFO 和 PHP_SELF 就清楚了)。