工作中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 在逐渐生成了

 

 那么让那段耗时的代码自己在后面慢慢执行的效果就达到了

posted @ 2017-03-01 16:08  李照耀  阅读(1981)  评论(0编辑  收藏  举报