工作中php处理HTTP请求的缺陷总结
之前遇到过php在处理一部分业务的时候总是感觉有短板,有些东西总是不能随人心意。比如执行时间问题,一个进程需要读取多条数据放入数组循环执行处理流程,就会很慢,容易超时,这个超时问题 可以用php设置set_time_limit(0);来解决,但是仍然感觉有点不合理。有些时候如果不需要拿到返回结果还好,如果需要得到返回结果,这个超时成504就给人很不好的体验。
后来我想到采用一个进程来处理返回数据给http,另起一个curl去处理那些时间很长很复杂的业务,但是这样的话 就会curl一直等待着新请求直到结束。直到我发现 curl可以设置超时时间,就解决了这边的问题,让用户先感受到 请求已经结束,然后后面的进程实际上在暗中执行,前台中如果用户需要看到执行效果,可以设置一个提示正在处理中,避免他看到数据还没有处理完成的尴尬。
这样的业务出现很多次了,在之前做同步粉丝信息的时候就遇到过。几万个粉丝需要同步下来信息,30秒的超时显然是不够的,就需要提前返回处理信息给用户才行。
还有一次是需要调用别人的接口的业务,本来用户不关心调接口的那个业务,请求可以很快结束掉的,但是调用接口这一步等待时间过久,就会造成前端卡顿体验效果不大好这样的损失,给业务的处理带来很头疼的不必要的性能损失。
解决方案出现:
采用异步交互
在采用异步交互的时候,需要把你要处理的业务先放入一个队列,然后立即返回成功,这样前面用户就不会出现等待卡死的问题。那么问题来了,如何让队列里面的任务自动执行呢?
这里还是推荐使用定时脚本去跑一下,根据合适的数据量 设定脚本运行时间间隔为多久。
当然如果不采用异步的话 有地方如果用户不关心返回结果可以采用同步,但是有的业务要求超时时间很短,就需要设置超时时间为毫秒级,如何设置呢?请看我的另一篇文章
http://www.cnblogs.com/lizhaoyao/p/5640887.html
当然 除了能在curl控制超时时间外我们还可以通过fsocket异步访问来获取数据。
例如 访问这个
<?php // 远程请求(不获取内容)函数,下面可以反复使用 function _sock($url) { $host = parse_url($url,PHP_URL_HOST); $port = parse_url($url,PHP_URL_PORT); $port = $port ? $port : 80; $scheme = parse_url($url,PHP_URL_SCHEME); $path = parse_url($url,PHP_URL_PATH); $query = parse_url($url,PHP_URL_QUERY); if($query) $path .= '?'.$query; if($scheme == 'https') { $host = 'ssl://'.$host; } $fp = fsockopen($host,$port,$error_code,$error_msg,1); if(!$fp) { return array('error_code' => $error_code,'error_msg' => $error_msg); } else { stream_set_blocking($fp,true);//开启了手册上说的非阻塞模式 stream_set_timeout($fp,1);//设置超时 $header = "GET $path HTTP/1.1\r\n"; $header.="Host: $host\r\n"; $header.="Connection: close\r\n\r\n";//长连接关闭 fwrite($fp, $header); usleep(1000); // 这一句也是关键,如果没有这延时,可能在nginx服务器上就无法执行成功 fclose($fp); return array('error_code' => 0); } } _sock('http://localhost/php_file/file.php'); echo "after fsocket";
然后在这个 localhost 下面的 php_file 里面的file.php里面写一个循环创建文件的代码 每秒钟创建一个文件
<?php $act = isset($_GET['act']) ? $_GET['act'] : ""; $i=100; while ($i<200) { $i++; $file_name = $i . "_data.txt"; if ($act == '') { sleep(1); file_put_contents($file_name, date("Y-m-d H:i:s",time())); } elseif ($act == 'del') { unlink($file_name); } }
之后执行 fsocket 的代码
迅速打印了 “after fsocket“
然后你就看到那个 101_data.txt 到 200_data.txt 在逐渐生成了
那么让那段耗时的代码自己在后面慢慢执行的效果就达到了