在开发中,遇到这样一个需求,客户端想要批量请求一批数据,但客户端并不想等待批量处理的结果,这就要求服务端收到数据后判定了数据格式正确之后,告诉给客户端我已经收到了请求,然后另外开启一个进程去处理批量的数据,这样的需求可以用fsocketopen来实现。
下面的代码支持发送序列化的json数据,并且支持cookie权限认证,保证调用的接口也拥有相应的权限。
主要包含以下几个关键点:
首先解析请求的url,获取主机、端口、路径、以及query
处理传过来的cookie对象,笔者使用的是yii框架,cookie可以这样获取:
$cookie = Yii::app()->request->cookies
设置完整的请求头内容,包括请求方法、主机名,cookie、content-type,content-length、connection、以及携带的post数据。
注意接收文件或者action应该采用file_get_contents('php://input')的方法来获取到传递的post数据。
debug参数是否开启,如果开启了那么异步将不生效,方便调试。
function request_by_fsockopen($url, $post_data, $cookie, $debug=false){
$url_array = parse_url($url);
$hostname = $url_array['host'];
$port = isset($url_array['port'])? $url_array['port'] : 80;
$requestPath = $url_array['path'] ."?". $url_array['query'];
$fp = fsockopen($hostname, $port, $errno, $errstr, 10);
if (!$fp) {
echo "$errstr ($errno)";
return false;
}
$cookie_str = '';
foreach ($cookie as $k => $v) {
$cookie_str .= urlencode($k) .'='. urlencode($v) .'; ';
}
$method = "GET";
if(!empty($post_data)){
$method = "POST";
}
$header = "$method $requestPath HTTP/1.1\r\n";
$header.="Host: $hostname\r\n";
$crlf = "\r\n";
if (!empty($cookie_str)) {
$header .= 'Cookie: '. substr($cookie_str, 0, -2) . $crlf;
}
if(!empty($post_data)){
$_post = json_encode($post_data);
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";//POST数据
$header .= "Content-Length: ". strlen($_post) ."\r\n";//POST数据的长度
$header.="Connection: Close\r\n\r\n";//长连接关闭
$header .= $_post . "\r\n\r\n"; //传递POST数据
}
else{
$header.="Connection: Close\r\n\r\n";//长连接关闭
}
fwrite($fp, $header);
usleep(1000);
//-----------------调试代码区间-----------------
//注如果开启下面的注释,异步将不生效可是方便调试
if($debug){
$html = '';
while (!feof($fp)) {
$html.=fgets($fp);
}
}
//-----------------调试代码区间-----------------
fclose($fp);
}