摘要:正常情况下,PHP执行的都是同步请求,代码自上而下依次执行,但有些场景如发送邮件、执行耗时任务等操作时就不适用于同步请求,只能使用异步处理请求。场景要求:客户端调用服...
正常情况下,PHP执行的都是同步请求,代码自上而下依次执行,但有些场景如发送邮件、执行耗时任务等操作时就不适用于同步请求,只能使用异步处理请求。
场景要求:
客户端调用服务器 a.php 接口,需要执行一个长达 10s-20s 不等的耗资源操作,假如客户端响应请求时间为5秒(请求响应超时时间),5s 以上无回复即断开连接。
解决设想:
客户端调用 a.php 之后,a.php 执行异步多线程操作调用 b.php,a.php 调用成功后即刻反馈给客户端回执,b.php 自动执行耗资源操作。
方案:
利用 fsockopen() 方法解决PHP异步请求
1.封装异步请求函数 asyncRequest(),代码如下:
/** * php异步请求 * @param $url string 请求Url * @param $post array POST参数 * @return string */ function asyncRequest($url, $post = array()){ $matches = parse_url($url); !isset($matches['host']) && $matches['host'] = ''; !isset($matches['path']) && $matches['path'] = ''; !isset($matches['query']) && $matches['query'] = ''; !isset($matches['port']) && $matches['port'] = 80; P($matches); $host = $matches['host']; $port = $matches['port']; $path = $matches['path'] ? $matches['path'].($matches['query'] ? '?'.$matches['query'] : '') : '/'; $post = $post && is_array($post) ? http_build_query($post) : ''; $errno = 0; $errstr = ''; $timeout = 30; //连接超时时间(S) if(function_exists('fsockopen')) { $fp = @fsockopen($host, $port, $errno, $errstr, $timeout); } elseif (function_exists('pfsockopen')) { $fp = @pfsockopen($host, $port, $errno, $errstr, $timeout); } elseif (function_exists('stream_socket_client')) { $fp = @stream_socket_client('tcp://'.$host.':'.$port, $errno, $errstr, $timeout); } else { $fp = false; } if (!$fp) { return '连接失败'; } if ($errno || !$fp) { return $errstr; } $out = "POST $path HTTP/1.1\r\n"; $out .= "Accept: */*\r\n"; //$out .= "Referer: $Referer\r\n"; $out .= "Accept-Language: zh-cn\r\n"; $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; $out .= "User-Agent: ".$_SERVER['HTTP_USER_AGENT']."\r\n"; $out .= "Host: $host\r\n"; $out .= 'Content-Length: '.strlen($post)."\r\n"; $out .= "Connection: Close\r\n"; $out .= "Cache-Control: no-cache\r\n"; $out .= $post; stream_set_blocking($fp, false); //非阻塞 stream_set_timeout($fp, $timeout);//响应超时时间(S) $result = @fwrite($fp, $out); @fclose($fp); return $result; }
2.正常接口 a.php,如下:
$url = 'http://localhost/b.php'; $param = array( 'istest' => 1, ); $asyncData = asyncRequest($url, $param); echo 'a.php success';
3.耗时接口 b.php,如下:
set_time_limit(0); ignore_user_abort(true);//设置与客户机断开是否会终止执行 fastcgi_finish_request();//提高请求的处理速度 sleep(15); echo "耗时15秒";
网友评论:
实用
2023-10-07 20:22:43 回复