PHP函数file_get_contents()访问腾讯云CDN地址超时的问题
最近把一个域名迁移到了腾讯云CDN上,结果其他php程序出现了超时打不开的情况,最终定位到原因竟是,php代码中的file_get_contents()获取了用了腾讯云CDN的网址导致超时。
复现该问题很简单,php写一行代码打开一个用了腾讯云CDN的网址文件:
echo file_get_contents('http://cdn.wms.rj1111.top/badman.txt');60s才能打开页面,网上参阅了一些资料,确认腾讯云CDN服务器没有回复FIN ANK导致的,必须等待CDN侧所设定的socket时间超时后才算结束
具体可以参考这一篇文章,作者写的非常详细:
https://www.jianshu.com/p/42e0c4304b60
解决方法:
方法1、给file_get_contents()函数加上超时时间,如0.5s
$opts = array("http" => array("method" => "GET", "timeout" => 0.5));
$context = stream_context_create($opts);
$result = @file_get_contents('http://cdn.wms.rj1111.top/badman.txt', false, $context);问题是,0.5s无法保证网络已经获取到了此文件,如果超时时间设置过长,又导致程序访问缓慢,不推荐此方法
方法2、弃用file_get_contents(),改用curl封装自定义函数来访问,例如:
$data = http($url, $params, $method = 'GET', array(), false);
function http($url, $params, $method = 'GET', $header = array(), $multi = false)
{
$opts = array(
CURLOPT_TIMEOUT => 3,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => 0, // 调试开启
);
/* 根据请求类型设置特定参数 */
switch (strtoupper($method)) {
case 'GET':
$opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
break;
case 'POST':
// 提交原始数据$multi=true
$params = $multi ? $params : http_build_query($params);
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $params;
break;
case 'PUT':
$params = $multi ? $params : http_build_query($params);
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_CUSTOMREQUEST] = 'PUT';
$opts[CURLOPT_POSTFIELDS] = $params;
break;
case 'DELETE':
$params = $multi ? $params : http_build_query($params);
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
$opts[CURLOPT_POSTFIELDS] = $params;
break;
default:
exit('不支持的请求方式!');
//throw new Exception('不支持的请求方式!');
}
/* 初始化并执行curl请求 */
$ch = curl_init();
curl_setopt_array($ch, $opts);
$data = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
exit('请求发生错误:' . $error);
//throw new Exception('请求发生错误:' . $error);
}
return $data;
}此方法可完美解决,推荐使用
方法3、如果不想改动太多代码,那么绑定一个不带CDN直接解析源站IP的域名来调用即可,例如:
echo file_get_contents('http://no-cdn.wms.rj1111.top/badman.txt');这是最低成本的改动方式,推荐使用