PHP执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。
例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。
而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了。这时候就需要采用异步的方式执行。
众所周知,PHP没有直接支持多线程这种东西。我们可以采用折衷的方式实现。这里主要说的就是fsockopen
。
通过fsockopen发送请求并忽略返回结果,程序可以马上返回。
示例代码:
$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); /*忽略执行结果 while (!feof($fp)) { echo fgets($fp, 128); }*/ fclose($fp); }
需要注意的是我们需要手动拼出header头信息。通过打开注释部分,可以查看请求返回结果,但这时候又变成同步的了,因为程序会等待返回结果才结束。
实际测试的时候发现,不忽略执行结果,调试的时候每次都会成功发送sock请求;但忽略执行结果,经常看到没有成功发送sock请求。查看Nginx日志,发现很多状态码为499的请求。
后来找到了原因:
fwrite
之后马上执行fclose
,Nginx会直接返回499,不会把请求转发给PHP处理。
客户端主动端口请求连接时,Nginx 不会将该请求代理给上游服务(FastCGI PHP 进程),这个时候 access log 中会以 499 记录这个请求。
解决方案:
# 忽略客户端中断 fastcgi_ignore_client_abort on;
2)fwrite之后使用usleep函数休眠20毫秒:
usleep(20000);
后来测试就没有发现失败的情况了。
附上完整代码:
<?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); //忽略执行结果;否则等待返回结果 // if(APP_DEBUG === true){ if(false){ $ret = ''; while (!feof($fp)) { $ret .= fgets($fp, 128); } } usleep(20000); //fwrite之后马上执行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); //忽略执行结果;否则等待返回结果 // if(APP_DEBUG === true){ if(false){ $ret = ''; while (!feof($fp)) { $ret .= fgets($fp, 128); } } usleep(20000); //fwrite之后马上执行fclose,Nginx会直接返回499 fclose($fp); } } ?>
原文地址:https://www.jb51.cc/php/1211048.html
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。