一、背景
前天中午同事问我一个问题,他有一个需求就是在某个页面中需要调用一下第三方的一个地址,目的是第三方会根据你发的请求做一个统计。
问题分析:
1:对终端用户来说这个接口调用完全没有意义
2:如果接口响应(建立连接时间+响应时间)过慢,那么就会影响用户体验。
理想状态:
在页面的某个点捅一下这个接口完事,瞬间就继续往下走。
二、解决方案
1:当时我首先想到的解决方案是用curl的异步,设置建立连接的时间稍微长一点,但是响应时间设置为毫秒级。
代码如下:
<?php
$nodes = array('http://consis.learn.com/curl/c.php', 'http://consis.learn.com/curl/d.php');
$node_count = count($nodes);
$curl_arr = array();
$master = curl_multi_init();
for($i = 0; $i < $node_count; $i++) {
$url =$nodes[$i];
$curl_arr[$i] = curl_init($url);
curl_setopt($curl_arr[$i], CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_arr[$i], CURLOPT_CONNECTTIMEOUT, 1); //建立连接等待时间
curl_setopt($curl_arr[$i], CURLOPT_TIMEOUT_MS, 10);//响应超时时间
curl_multi_add_handle($master, $curl_arr[$i]);
}
do {
curl_multi_exec($master,$running);
} while($running > 0);
echo "results: ";
for($i = 0; $i < $node_count; $i++) {
$results = curl_multi_getcontent ( $curl_arr[$i] );
echo( $i . "\n" . $results . "\n");
}
echo 'done';
其中c.php和d.php的代码如下:
c.php:
<?php
error_log(date("Y-m-d H:i:s") . "\there1\n", 3, "/tmp/a.log");
sleep(5);
error_log(date("Y-m-d H:i:s") . "\there2\n", 3, "/tmp/a.log");
echo 'test a b c';
d.php:
<?php
echo "this is c d e f g";
这样做基本可以实现效果,但是还是不完美,因为虽然这样虽然基本可以忽略对方的响应时间,但是避免不了建立连接花费的时间,如果和对方距离过长,中间网络问题都有可能达到最大值,而且这个最大值也不能设置太大,还会造成数据丢失问题问题:比如你设置1秒,而如果1秒还未建立连接成功,那么其实对方是收不到这次请求的。
2:第二种方案很完美的解决了这个问题,是我同事自己想出来的。
用的是curl+exec