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就是自动处理这个动态页了。
![](http://img.blog.csdn.net/20170404175516680?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVsZW5feHVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
开启cmd,开启一个php-cgi来监听9001端口,记得在php-cgi.exe以及php.ini前加上它们所在的路径,或者像我的图里的一样,进入它们所在的文件夹里再进行操作。
![](http://img.blog.csdn.net/20170404175728395?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmVsZW5feHVl/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
开启后会打开一个黑色窗口,这个是php-cgi的程序正在运行,不能关闭。
下面使用index.php来做个范例
index.php
<?php
echo file_get_contents("http://localhost:8080/ceshi.php");
ceshi.php
<?php
echo 3;
浏览器的结果:
这个问题出现的原因:
首先我们来看问题产生的情境:我们在本地服务器的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;
浏览器的结果:
相关文章推荐
- PHP无法使用file_get_contents或者curl_init()函数解决办法
- php读取网络文件curl,fsockopen,file_get_contents,file,fopen几种方法
- PHP使用fopen与file_get_contents读取文件实例分享
- nginx+fastcgi php 使用file_get_contents、curl、fopen读取localhost本站点.php异常的情况
- PHP使用fopen与file_get_contents读取文件实例分享
- PHP使用curl替代file_get_contents
- PHP读取文件函数fread,fgets,fgetc,file_get_contents和file函数的使用总结
- PHP中curl_init和file_get_contents配合使用
- 使用PHP的curl扩展实现跨域post请求,以及file_get_contents()百度短网址例子
- php中使用Curl、socket、file_get_contents三种方法POST提交数据
- php读取网络文件(curl, fsockopen ,file_get_contents 几个方法的效率对比)
- php 使用file_get_contents读取大文件的方法
- php 在linux 用fopen() 函数打开,file_get_contents(),fread()函数 读取 另外一台服务器映射过来的文件 总是返回false,null的情况。
- PHP用file_get_contents读取https的链接错误解决办法
- php fopen,file_get_contents,curl的区别
- PHP中使用file_get_contents抓取网页中文乱码问题解决方法
- php读取网络文件 curl, fsockopen ,file_get_contents 几个方法的效率对比
- PHP使用curl替代file_get_contents
- 在PHP中使用CURL访问HTTPS时出现certificate verify failed解决办法
- php 调试微信接口时curl无返回值,file_get_contents有返回值的解决方法