nginx设置pathinfo功能,适配thinkphp5的路由模式。

heimicms 2019-09-08

最近在部署用thinkphp5写的项目到Centos7上,用的是nginx,部署好后发现验证码出不来了,分析一波之后发现nginx无法解析thinkphp的路由规则,所以出现了404错误。网上的教程有些真心不错,有些真的是复制粘贴的。真是走了一大波弯路。于是把自己的经验写一下。

我用的是nginx1.14版本的,这次的部署中,官网的手册真心重要,建议要多多看官网手册。我这次会说明两种形式的写法。

第一种

location / {
        root   /usr/share/nginx/html;
        index  index.php;
    if (!-e $request_filename) {
        rewrite ^/meeting/public/(.*)$ /meeting/public/index.php?s=$1 last;
    }
}       

 

location ~ \.php {
     fastcgi_pass   127.0.0.1:9000;
     fastcgi_index  index.php;
     fastcgi_param  SCRIPT_FILENAME  /usr/share/nginx/html$fastcgi_script_name;
     include        fastcgi_params;
 }

这里我们先看看第一个location的rewirite,官网是这样解释的:如果指定的正则表达式与请求URI匹配,则按照替换字符串中的指定更改URI。重写指令按照它们在配置文件中的出现顺序执行。
nginx设置pathinfo功能,适配thinkphp5的路由模式。

简单来说就是url根据你的正则表达式进行变换,以上面第一个location块来说,假设url为/meeting/public/aaa/bbb/ccc,根据正则就会替换为 /meeting/public/index.php?s=aaa/bbb/ccc,其中$1就是(.*)$匹配到的,如果你有多个正则,程序将会赋值给$2,$3.........,这样thinkphp就能通过$_GET['s']获取到。然后把请求转给第二个location块,这样就能访问了。

但是这样也是有弊端的,如果我手痒痒,把?s=xxx,写成?g=xxx呢?那当然没什么用了,我记得thinkphp使用的是?s=xxx,或者我直接访问/meeting/public/index.php/aaa/bbb/ccc呢,根据上面的正则表达式,我们就发现也是不行的。因为根本没有访问第一个location,而是直接访问第二个location块,第二个location并没有实现pathinfo的能力。于是访问失败。

这里请注意,如果第二个location是location ~ .php$ {,记得把$去掉。

第二种方法

location / {
        root   /usr/share/nginx/html;
        index  index.php;
        if (!-e $request_filename) {
                rewrite ^/meeting/public/(.*)$ /meeting/public/index.php/$1 last;
        }
    }
    
 location ~ \.php {
     fastcgi_pass   127.0.0.1:9000;
     fastcgi_index  index.php;
     fastcgi_split_path_info       ^(.+\.php)(.*)$;
     fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name;
     fastcgi_param PATH_INFO       $fastcgi_path_info;
     include        fastcgi_params;
 }

第一个location的rewirite表达的正则其实跟前面差不多,假设url为/meeting/public/aaa/bbb/ccc,根据正则就会替换为 /meeting/public/index.php/aaa/bbb/ccc,然后转发给第二个location,第二个location使用了fastcgi_split_path_info。手册对这个的说明是这样的:定义一个正则表达式,该表达式捕获$fastcgi_path_info变量的值。正则表达式应该有两个捕获:第一个捕获成为$fastcgi_script_name变量的值,第二个捕获成为$fastcgi_path_info变量的值。可以看看官网对着两个变量的解释。
nginx设置pathinfo功能,适配thinkphp5的路由模式。

这里第二个location通过fastcgi_split_path_info方法,将/meeting/public/index.php/aaa/bbb/ccc根据正则分成两个,一个是/meeting/public/index.php,赋值给$fastcgi_script_name,aaa/bbb/ccc赋值给$fastcgi_path_info。接着将$fastcgi_script_name通过fastcgi_param赋值给SCRIPT_FILENAME,再传递给php服务器。$fastcgi_path_info也是一样。注意,这里的SCRIPT_FILENAME和PATH_INFO是$_SERVER超级全局变量的键名,不能写错。通过这种方法,我们的第二个location块也具备了pathinfo的能力,并且克服了第一种方法的不足之处。

相关推荐