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

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;

浏览器的结果:





没有更多推荐了,返回首页