您的位置:首页 > 运维架构 > Nginx

windows nginx使用file_get_contents、fopen、curl访问php文件造成阻塞的解决办法

2017-04-04 18:26 1641 查看
windows nginx造成的file_get_contents、fopen、curl在访问本地php文件造成阻塞的问题相信很多人都遇到过,关于这个问题涉及到了php的运行等问题,有兴趣的可以先去看我上一篇博客对php运行的讲解php的运行原理、cgi对比fastcgi以及php-cgi和php-fpm之间的联系区别。这个问题有许多博客都讲解过,不过在我解决问题的过程中我发现许多博客写的要么不够完整,要么就是有部分错误的地方,所以这里重新整理一下自己对这个问题的解决过程,希望能帮助其他的人。

这个问题出现的原因:

首先我们来看问题产生的情境:我们在本地服务器的www文件夹内的ceshi.php文件中使用file_get_content('http://localhost/index.php'),fopen和curl是同样的原因下面不赘述。

获取本地的index.php文件中的内容时,这是作为访问一个url处理的,而index.php是一个动态页面,这个时候就会产生一个问题,原本我们访问ceshi.php文件时,就是作为一个php文件处理,这个时候http服务器nginx通过fast-cgi协议将ceshi.php分配给一个php-cgi程序进行处理,一般情况下这个php-cgi解析完ceshi.php的数据后返回数据。

但是由于file_get_contents获取的是一个通过http协议取得的动态文件index.php,这等于是我们给nginx发送了两个http请求,但是windows系统只加载了一个http进程,因此只能先处理第一个,也就是ceshi.php的请求,但是ceshi.php的file_get_contents一直在等待index.php的请求结果,但是这个请求没有http进程处理,所以一直等待,因此造成了阻塞,如果还不太明白看看下面。

下面是nginx的配置文件的一段,这里所有来自php的文件都由fast-cgi来处理:

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;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}

windows中是开启一个php-cgi对来自127.0.0.1:9000的连接请求进行监听,一旦接收到9000端口的连接请求就进行处理,所以在本地服务器收到80端口的浏览器请求后,如果是静态页会直接返回静态页数据,如果是动态页,会发送连接请求给9000端口,然后php-cgi进行处理,这里的问题是浏览器同时发送了两个动态请求,但9000端口的php-cgi它只能处理一个请求,而这个请求等待另一个请求的结果导致阻塞。

这也就是为什么同样是file_get_contents("http://www.baidu.com")和file_get_contents("http://localhost/index.html")会正常获取到页面的原因,因为http://www.baidu.com和http://localhost/index.html获取到的页面是静态的,无须9000端口的php-cgi进行处理,因此不会出现阻塞的情况。

解决方案:看到上面对阻塞问题的解析,解决方案就简单了,既然是因为9000端口的php-cgi只能处理一个请求,那么我们就开启另一个php-cgi监听的端口来处理这个问题,但这还有一个问题,第二个请求我们怎么保证是由我们新开启的php-cgi监听端口来处理呢,这里的办法是我们还要开启另外一个端口来处理第二个http请求,所以我们需要开启一个后新的http服务,在新的http服务里指定fastcgi的端口为之前我们新开启的监听端口,这样该http请求的动态页面就会分配给这个php-cgi的监听端口来处理。

首先打开nginx的配置文件,复制server{...}的内容,一定记得全部复制,将监听的端口改为8080,这就是我们新开启的http服务端口,将里面的fastcgi_pass的端口9000改为9001,也就是说接受到8080端口的动态页面请求,会将该连接自动分配给9001端口,这个时候监听9001端口的php-cgi就是自动处理这个动态页了。



开启cmd,开启一个php-cgi来监听9001端口,记得在php-cgi.exe以及php.ini前加上它们所在的路径,或者像我的图里的一样,进入它们所在的文件夹里再进行操作。



开启后会打开一个黑色窗口,这个是php-cgi的程序正在运行,不能关闭。

下面使用index.php来做个范例

index.php

<?php
echo file_get_contents("http://localhost:8080/ceshi.php");

ceshi.php
<?php
echo 3;

浏览器的结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息