您好,登錄后才能下訂單哦!
php執(zhí)行一段程序,有可能幾毫秒就執(zhí)行完畢,也有可能耗時較長。
例如,用戶下單這個事件,如果調(diào)用了些第三方服務(wù)進(jìn)行發(fā)郵件、短信、推送等通知,可能導(dǎo)致前端一直在等待。
而有的時候,我們并不關(guān)心這些耗時腳本的返回結(jié)果,只要執(zhí)行就行了。這時候就需要采用異步的方式執(zhí)行。
眾所周知,PHP沒有直接支持多線程這種東西。我們可以采用折衷的方式實(shí)現(xiàn)。這里主要說的就是fsockopen
。
通過fsockopen發(fā)送請求并忽略返回結(jié)果,程序可以馬上返回。
示例代碼:
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30); if (!$fp) { echo "$errstr ($errno)<br />\n"; } else { $out = "GET /backend.php HTTP/1.1\r\n"; $out .= "Host: www.example.com\r\n"; $out .= "Connection: Close\r\n\r\n"; fwrite($fp, $out); /*忽略執(zhí)行結(jié)果 while (!feof($fp)) { echo fgets($fp, 128); }*/ fclose($fp); }
需要注意的是我們需要手動拼出header頭信息。通過打開注釋部分,可以查看請求返回結(jié)果,但這時候又變成同步的了,因為程序會等待返回結(jié)果才結(jié)束。
實(shí)際測試的時候發(fā)現(xiàn),不忽略執(zhí)行結(jié)果,調(diào)試的時候每次都會成功發(fā)送sock請求;但忽略執(zhí)行結(jié)果,經(jīng)??吹?jīng)]有成功發(fā)送sock請求。查看nginx日志,發(fā)現(xiàn)很多狀態(tài)碼為499的請求。
后來找到了原因:
fwrite
之后馬上執(zhí)行fclose
,nginx會直接返回499,不會把請求轉(zhuǎn)發(fā)給php處理。
客戶端主動端口請求連接時,NGINX 不會將該請求代理給上游服務(wù)(FastCGI PHP 進(jìn)程),這個時候 access log 中會以 499 記錄這個請求。
解決方案:
1)nginx.conf增加配置
# 忽略客戶端中斷 fastcgi_ignore_client_abort on;
2)fwrite之后使用usleep函數(shù)休眠20毫秒:
usleep(20000);
后來測試就沒有發(fā)現(xiàn)失敗的情況了。
附上完整代碼:
<?php /** * 工具類 * */ class FsockService { public static function post($url, $param){ $host = parse_url($url, PHP_URL_HOST); $port = 80; $errno = ''; $errstr = ''; $timeout = 30; $data = http_build_query($param); // create connect $fp = fsockopen($host, $port, $errno, $errstr, $timeout); if(!$fp){ return false; } // send request $out = "POST ${url} HTTP/1.1\r\n"; $out .= "Host:${host}\r\n"; $out .= "Content-type:application/x-www-form-urlencoded\r\n"; $out .= "Content-length:".strlen($data)."\r\n"; $out .= "Connection:close\r\n\r\n"; $out .= "${data}"; fwrite($fp, $out); //忽略執(zhí)行結(jié)果;否則等待返回結(jié)果 // if(APP_DEBUG === true){ if(false){ $ret = ''; while (!feof($fp)) { $ret .= fgets($fp, 128); } } usleep(20000); //fwrite之后馬上執(zhí)行fclose,nginx會直接返回499 fclose($fp); } public static function get($url, $param){ $host = parse_url($url, PHP_URL_HOST); $port = 80; $errno = ''; $errstr = ''; $timeout = 30; $url = $url.'?'.http_build_query($param); // create connect $fp = fsockopen($host, $port, $errno, $errstr, $timeout); if(!$fp){ return false; } // send request $out = "GET ${url} HTTP/1.1\r\n"; $out .= "Host:${host}\r\n"; $out .= "Connection:close\r\n\r\n"; fwrite($fp, $out); //忽略執(zhí)行結(jié)果;否則等待返回結(jié)果 // if(APP_DEBUG === true){ if(false){ $ret = ''; while (!feof($fp)) { $ret .= fgets($fp, 128); } } usleep(20000); //fwrite之后馬上執(zhí)行fclose,nginx會直接返回499 fclose($fp); } } ?>
以上就是php中使用fsockopen實(shí)現(xiàn)異步請求(代碼示例)的詳細(xì)內(nèi)容,更多請關(guān)注億速云其它相關(guān)文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。