前戏

如果想用php实现一个http异步请求,是否能做到呢?

正题

答案是肯定的,以下是的socket解决方案:

function makeRequestAsync($url, $params = array(), $type='POST')
{
    $query_string = '';
    if(is_array($params) && !empty($params))
        $query_string = http_build_query($params);
    elseif(is_string($params))
        $query_string = $params;

    $type = strtoupper($type);

    $parts=parse_url($url);

    $fp = fsockopen($parts['host'], isset($parts['port']) ? $parts['port'] : 80, $errno, $errstr, 1);
    if('GET' == $type) $parts['path'] .= '?'.$query_string;

    $out = "$type ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['host']."\r\n";
    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
    if ('POST' == $type) $out.= "Content-Length: ".strlen($query_string)."\r\n";
    $out.= "Connection: Close\r\n\r\n";
    if ('POST' == $type && isset($query_string)) $out.= $query_string;
    fwrite($fp, $out);
    stream_set_timeout($fp, 1);
    fclose($fp);
}

测试

测试方法:

client.php

makeRequestAsync('http://127.0.0.1/async/server.php');
makeRequestAsync('http://127.0.0.1/async/server.php');
makeRequestAsync('http://127.0.0.1/async/server.php');
makeRequestAsync('http://127.0.0.1/async/server.php');
makeRequestAsync('http://127.0.0.1/async/server.php');
makeRequestAsync('http://127.0.0.1/async/server.php');
echo 'done';

server.php

sleep(6);
file_put_contents(uniqid(), '');
echo 'x';

用浏览器打开client.php看到瞬间执行完毕,但async目录里面需要6秒后才会生成文件,成功了。

多说两句

这里需要注意两个地方,一个是fsockopen的超时时间,这个时间需要设置得小一点,如果一个ip是无法访问到的,并且超时时间很长的话,这个socket连接需要等到过了这个超时时间才会执行后续代码。这样会导致代码卡死。另外这个方法是否无法处理server端的返回的。

另一个是stream流的超时时间,也就是fwrite流的超时时间stream_set_timeout,这个也需要设置小一点,这里将两个超时时间都设置成了1秒。实际运用中可能需要设置成更小的值。

所以这个方法也是有缺陷的,就是可能会丢失数据,有请求超时的风险。

如果您觉得您在我这里学到了新姿势,博主支持转载,姿势本身就是用来相互学习的。同时,本站文章如未注明均为 hisune 原创 请尊重劳动成果 转载请注明 转自: php的异步http请求解决方案 - hisune.com