这是我项目的坑,之前产品部门反映说,微信二维码的加载页面打开很慢,接到任务后,我第一时间去排查。经过不断的调试,我终于定位问题,出问题的关键代码如下
private function getQrcode($url)
{
//用户头像内容
$avatarString = file_get_contents(AgentUsersWechat::getUserAvatar());
$png = QrCode::format('png')->size(600)->mergeString($avatarString)->margin(2)->generate($url);
return 'data:image/png;base64,' . chunk_split(base64_encode($png));
}
}
这段代码导致的问题,他是用file_get_contents在获取用户的头像图片,网上找了一遍 终于找到了答案。说是用curl代替file_get_contents可以加快速度。
下面是我摘抄的解释,大家可以看下
通过抓包调试,我们知道了首先是微信服务器在返回完HTTP响应后并不会马上关闭,而且HTTP头的设置并不是Connect:keep-alive而是Connect:close,所以并不要求服务端维护一段时间长连接,因为file_get_contents的实现是通过不断循环调用socket的recv方法的返回值来判断是否读完所以导致了file_get_contents在微信服务端连接未关闭的时候会一直阻塞等待最后一个关闭回复的FIN ACK包,这就导致了file_get_contents获取微信头像会耗时长的原因。
而CURL则是优先按照HTTP响应头的Content-Length大小来读,并不像filet_get_contents是不断循环调用socket的recv,然后靠recv返回值来判断是否读完,CURL则是读完Content-Length个字节后马上主动关闭连接,所以就不存在等待对端连接关闭了。
作者:lambdacalculus
链接:https://www.jianshu.com/p/42e0c4304b60
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
大致的意思是说 file_get_contents和curl对http协议的处理方式不一样。而curl更好一些。所以我马上把这个代码换成curl了。
我用了一个方法处理。代码如下
private static function getImage($url )
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_ENCODING, ""); //加速 这个地方留空就可以了
curl_setopt($ch, CURLOPT_HEADER, 0);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
/**
* 获取二维码地址
* @param int $uid 用户ID
* @param string $url url地址
* @return string
*/
private function getQrcode($url)
{
//用户头像内容
$avatarString = self::getImage(AgentUsersWechat::getUserAvatar());
$png = QrCode::format('png')->size(600)->mergeString($avatarString)->margin(2)->generate($url);
return 'data:image/png;base64,' . chunk_split(base64_encode($png));
}
然后改成这个后,产品反映的问题迎刃而解了。
总结:通过这件事。我可以反思到。我们写代码用php函数的时候,高手往往知道函数的底层调用机制。所以能够快速定位问题。说白了还是自己积累不够。http是一个很深的东西,需要我们不断的去琢磨。2个方法看起来作用差不到,没想到底层有这么大的区别。各位 希望共勉 一起进步。