php中使用fsockopen实现异步请求
转自: https://www.yisu.com/zixun/367919.html
还有一篇: https://www.laruence.com/2008/04/16/98.html
php中怎么使用fsockopen实现异步请求,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。
php执行一段程序,有可能几毫秒就执行完毕,也有可能耗时较长。
例如,用户下单这个事件,如果调用了些第三方服务进行发邮件、短信、推送等通知,可能导致前端一直在等待。
而有的时候,我们并不关心这些耗时脚本的返回结果,只要执行就行了。这时候就需要采用异步的方式执行。
众所周知,PHP没有直接支持多线程这种东西。我们可以采用折衷的方式实现。这里主要说的就是fsockopen
。
通过fsockopen发送请求并忽略返回结果,程序可以马上返回。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $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 记录这个请求。
解决方案:
1)nginx.conf增加配置
1 2 | # 忽略客户端中断 fastcgi_ignore_client_abort on; |
2)fwrite之后使用usleep函数休眠20毫秒:
1 | usleep(20000); |
后来测试就没有发现失败的情况了。
附上完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <?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 ); } } ?> |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析