慢慢赚钱博客

4月 9 2019

Nginx的CGI、FastCGI和PATHINFO

CGI
通用网关接口(Common Gateway Interface)是一个Web服务器主机提供信息服务的标准接口。通过CGI接口,Web服务器就能够获取客户端提交的信息,转交给服务器端的CGI程序进行处理,最后返回结果给客户端。

nginx把活代理给php-fpm,处理完交给nginx,返回给客户。

Nginx接收到php-fpm处理的结果后,就可以响应客户端的http请求给予一个回应了,客户端的这一次http请求就结束了,一张由php产生的华丽丽的网页就呈现在网民的面前。在这段对话中,nginx与php-fpm并没有相互推诿扯皮,交流的很顺畅;没有推诿扯皮的原因就是nginx与php-fpm之间的数据和消息传递使用了统一的标准格式,这个标准格式就是CGI,所以倘若nginx和php-fpm中有任何一方不按CGI标准来玩,你推诿扯皮也没用。

发展到现在,对CGI的理解可以是一种标准接口(协议规范),也可以理解成处理动态网页的某种语言,比如:php、asp都可以宽泛的看做是一种cgi,这个时候cgi就被泛化了但依然包含了不推诿扯皮的交流标准的这一层含义。

FastCGI
FastCGI的Fast已经表明含义了,是一种快速的CGI,也是现代动态网页语言与web server之间普遍所采用的。FastCGI像是一个常驻型的CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去fork一次(这是CGI最为人诟病的fork-and-execute 模式)。它还支持分布式的运算,即FastCGI程序可以在网站服务器以外的主机上执行并且接受来自其它网站服务器来的请求。

nginx与php-fpm就是采用的FastCGI模式。

PATHINFO
常常会见到这种格式的Urlhttps://blog.jjonline.cn/index.php/Article/Post/index.html ,这种Url理解有两种方式:

index.php当做一个目录看待:访问blog.jjonline.cn服务器根目录下的index.php目录下的Article目录下的Post目录下的index.html静态html文本文件;
index.php当做一个PHP脚本看待:访问blog.jjonline.cn服务器根目录下的index.php脚本,由该脚本产生html页面,Url中/Article/Post/index.html这一部分作为index.php脚本中使用的某种类型的参数。
绝大部分情况下,这种格式的Url理解方式是第二种,而/Article/Post/index.html这一部分理解成PATHINFO就好了。其实PATHINFO是一个CGI 1.1的一个标准,经常用来做为传参载体,只不过咱们没必要深入。

由于Apache的默认配置文件开启了PATHINFO的支持,Apache+PHP的环境下PATHINFO格式的Url可以不出任何错误的执行正确路径的PHP脚本并在脚本中使用PATHINFO中的参数。而Nginx默认提供的有关执行php-fpm运行PHP脚本的默认配置文件中并没有启用PATHINFO,从而导致了一个长久以来的误解:nginx不支持pathinfo。

早期版本的nginx确实不能直接支持pathinfo,但有变相的解决方法,网络上的一些配置nginx支持pathinfo的文章大多就是这种变相解决方法。nginx其实早已可以很简单的通过fastcgi_split_path_info指令支持pathinfo模式了,严格来说是nginx的0.7.31以上版本就可以使用这个指令了。

Nginx的PATHINFO配置
1、关于nginx配置指令的一些墨迹内容
默认的nginx是对http请求的uri进行正则匹配来决定这个请求是否要交给php-fpm来执行;nginx中有关是否要交给php-fpm这个cgi来解析执行某个php脚本的默认配置(nginx1.8.0)如下:

location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
上述location ~ \.php$这段是一个正则匹配,被匹配的内容是http请求的uri,正则表达式就是\.php$,而~则是nginx的location指令中的一个标记符,表示这个location匹配uri采用正则表达式来匹配;在这里URI和URL还是有区别,请厘清。正则表达式中$表示必须以某个字符或字符串结尾,这样上述默认配置中仅能匹配到以.php为结尾的uri交给php-fpm去解析,如下:

1、https://blog.jjonline.cn/index.php 匹配

2、https://blog.jjonline.cn/admin/index.php?m=Index&a=index 匹配,注意这里Url中有Get变量,nginx中location匹配的路径是uri,也就是虚拟路径部分,本例也就是:/admin/index.php

3、https://blog.jjonline.cn/admin/index.php/Index/index 不匹配,pathinfo模式,nginx将index.php理解成一个目录了,这种情况下的uri为:/admin/index.php/Index/index ,结尾并没有.php这种条件

正确配置Nginx对php的pathinfo支持,先要理解清楚nginx配置文件中是如何将某个请求交给php-fpm来执行的,以上述配置段为例来分析一下:

root:这个指令配置了php脚本的根目录,可以使用相对路径也可以使用绝对路径,上述示例中是html,表示php的根目录在nginx安装目录下的html目录;这里的目录一般与nginx配置文件server段下的root目录一致,也就是web服务器的根目录;且大多数的时候建议使用绝对地址。假设这里的root设置为:/var/www/www.jjonline.cn/wwwRoot,这样网站根目录的绝对地址就是/var/www/www.jjonline.cn/wwwRoot,配合各种ftp服务器端配置,将ftp登录的家目录设定为/var/www/www.jjonline.cn。拿ThinkPHP来举例:框架和核心模块文件可以放置在/var/www/www.jjonline.cn目录下,而入口文件放置在/var/www/www.jjonline.cn/wwwRoot下;这样框架和核心模块文件就不会被Url直接访问到。

fastcgi_pass:这个指令配置了fastcgi监听的端口,可以是TCP也可以是unix socket,这里一般推荐走TCP,这个TCP是由php-fpm配置文件决定的,不再详细介绍。

fastcgi_index:这个指令配置了fastcgi的默认索引文件,与server端下index指令类似。

fastcgi_param:这个指令配置了fastcgi的一些参数,传递给php-fpm,这个指令是3段式,第一段fastcgi_param指令名称,第二段传递给php-fpm的参数的名称,第三段传递给php-fpm参数的值,也就是说fastcgi_param配置了一系列的key-value类型的值;对PHP来说fastcgi_param指令产生的key-value键值对最后都(未确认,暂时这么理解吧~)转换成了超全局数组变量$_SERVER的键值对,上述示例中fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name就配置了一个SCRIPT_FILENAME的fastcgi参数,转换成PHP中的变量就是$_SERVER['SCRIPT_FILENAME'] ,PHP参考手册中对$_SERVER['SCRIPT_FILENAME']的说明是:“当前执行脚本的绝对路径”。对nginx来说,将请求正确的交给php-fpm来执行正确的php脚本就是由fastcgi_param指令配置的SCRIPT_FILENAME来决定的,所以nginx能默契的与php-fpm协作,fastcgi_param指令正确的配置了SCRIPT_FILENAME值是关键。

include:这个指令将指定的文本文件的内容作为配置项包含进来,与php中的include差不多意思,这个指令的参数就是一个配置文件的路径,可以是相对路径也可以是绝对路径,路径中可以使用通配符*;nginx的虚拟主机实现就使用到了这个指令,以及指令参数中使用到通配符。include fast