如何在PHP中创建异步GET请求?

Abs*_*Abs 94 php curl asynchronous http

我希望对另一台服务器上的另一个脚本发出一个简单的GET请求.我该怎么做呢?

在一种情况下,我只需要请求外部脚本而无需任何输出.

make_request('http://www.externalsite.com/script1.php?variable=45'); //example usage
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,我需要获取文本输出.

$output = make_request('http://www.externalsite.com/script2.php?variable=45');
echo $output; //string output
Run Code Online (Sandbox Code Playgroud)

说实话,我不想乱用CURL,因为这不是CURL的工作.我也不想使用http_get,因为我没有PECL扩展.

fsockopen会工作吗?如果是这样,如何在不读取文件内容的情况下执行此操作?没有其他办法吗?

谢谢大家

更新

我应该补充一下,在第一种情况下,我不想等待脚本返回任何内容.据我所知,file_get_contents()会等待页面完全加载等?

Mar*_*ang 49

file_get_contents 会做你想做的

$output = file_get_contents('http://www.example.com/');
echo $output;
Run Code Online (Sandbox Code Playgroud)

编辑:一种触发GET请求并立即返回的方法.

引自http://petewarden.typepad.com/searchbrowser/2008/06/how-to-post-an.html

function curl_post_async($url, $params)
{
    foreach ($params as $key => &$val) {
      if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
    }
    $post_string = implode('&', $post_params);

    $parts=parse_url($url);

    $fp = fsockopen($parts['host'],
        isset($parts['port'])?$parts['port']:80,
        $errno, $errstr, 30);

    $out = "POST ".$parts['path']." HTTP/1.1\r\n";
    $out.= "Host: ".$parts['host']."\r\n";
    $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
    $out.= "Content-Length: ".strlen($post_string)."\r\n";
    $out.= "Connection: Close\r\n\r\n";
    if (isset($post_string)) $out.= $post_string;

    fwrite($fp, $out);
    fclose($fp);
}
Run Code Online (Sandbox Code Playgroud)

这样做是打开一个套接字,触发一个get请求,然后立即关闭套接字并返回.

  • 这不是异步!特别是如果另一侧的服务器关闭,这段代码将挂起30秒(fsockopen中的第5个参数).fwrite也会花费很多时间来执行(你可以用stream_set_timeout($ fp,$ my_timeout)来限制.你能做的最好的事情是将fsockopen的低超时设置为0.1(100ms),$ my_timeout设置为100ms但是你有风险,请求超时. (60认同)
  • 这既不是异步也不是使用curl,你怎么敢称之为`curl_post_async`并得到甚至赞成... (14认同)
  • 我是否正确地说这个功能名称不正确?它实际上与curl库没有任何关系.这是fsock_post_async()更像它 (12认同)
  • curl_post_async发送POST请求,而不是GET. (5认同)
  • 这与异步无关.这是同步的......异步意味着在完成此任务时执行其他任务.它是并行执行. (4认同)
  • 是的,你为什么要一个POST请求?事实上,我认为HEAD请求最有意义. (3认同)
  • 需要注意的一件事是,如果请求的URL被重写(即服务器使用mod_rewrite),这种方法将无法正常工作.你需要使用像curl这样的东西. (2认同)

cat*_*ire 32

这是如何使Marquis的回答与POST和GET请求一起工作:

  // $type must equal 'GET' or 'POST'
  function curl_request_async($url, $params, $type='POST')
  {
      foreach ($params as $key => &$val) {
        if (is_array($val)) $val = implode(',', $val);
        $post_params[] = $key.'='.urlencode($val);
      }
      $post_string = implode('&', $post_params);

      $parts=parse_url($url);

      $fp = fsockopen($parts['host'],
          isset($parts['port'])?$parts['port']:80,
          $errno, $errstr, 30);

      // Data goes in the path for a GET request
      if('GET' == $type) $parts['path'] .= '?'.$post_string;

      $out = "$type ".$parts['path']." HTTP/1.1\r\n";
      $out.= "Host: ".$parts['host']."\r\n";
      $out.= "Content-Type: application/x-www-form-urlencoded\r\n";
      $out.= "Content-Length: ".strlen($post_string)."\r\n";
      $out.= "Connection: Close\r\n\r\n";
      // Data goes in the request body for a POST request
      if ('POST' == $type && isset($post_string)) $out.= $post_string;

      fwrite($fp, $out);
      fclose($fp);
  }
Run Code Online (Sandbox Code Playgroud)

  • 这不是异步!特别是如果另一侧的服务器关闭,这段代码将挂起30秒(fsockopen中的第5个参数).fwrite也会花费很多时间来执行(你可以用stream_set_timeout($ fp,$ my_timeout)来限制.你能做的最好的事情是将fsockopen的低超时设置为0.1(100ms),$ my_timeout设置为100ms但是你有风险,请求超时. (21认同)
  • 这是一个方便的代码片段,我一直在这里和那里使用它,但我现在发现我需要做同样的事情,但有一个SSL站点.除了HTTP/1.1类型和端口之外,还有什么我需要改变的吗? (2认同)
  • 在回答关于将此用于SSL的问题时,您可以通过将端口更改为443并将ssl://附加到fsockopen中的端口名称来使其成为SSL:$ fp = fsockopen("ssl://".$ parts ['host} "], (2认同)

dbr*_*dbr 13

关于您的更新,关于不想等待整页加载 - 我认为HTTP HEAD请求是您正在寻找的..

get_headers应该这样做 - 我认为它只请求头文件,因此不会发送整页内容.

"PHP/Curl:HEAD请求在某些站点上花费很长时间"描述了如何HEAD使用PHP/Curl 执行请求

如果你想要触发请求,而不是完全阻止脚本,有几种方法,具有不同的复杂性..

  • 执行HTTP请求作为后台进程,php执行后台进程 - 基本上你会执行类似的东西"wget -O /dev/null $carefully_escaped_url"- 这将是特定于平台的,你必须非常小心地将命令转义到命令
  • 在后台执行PHP脚本 - 基本上与UNIX进程方法相同,但执行PHP脚本而不是shell命令
  • 有一个"工作队列",使用数据库(或像beanstalkd这样的东西可能有点过分).您将URL添加到队列,后台进程或cron-job会定期检查新作业并对URL执行请求


Ala*_*orm 6

你没有.虽然PHP提供了许多调用URL的方法,但它并不提供对每个请求/执行周期进行任何类型的异步/线程处理的开箱即用支持.发送URL(或SQL语句等)请求的任何方法都将等待某种响应.您需要在本地计算机上运行某种辅助系统才能实现此目的(谷歌周围的"PHP作业队列")


sti*_*til 6

我建议你测试很好的PHP库:curl-easy

<?php
$request = new cURL\Request('http://www.externalsite.com/script2.php?variable=45');
$request->getOptions()
    ->set(CURLOPT_TIMEOUT, 5)
    ->set(CURLOPT_RETURNTRANSFER, true);

// add callback when the request will be completed
$request->addListener('complete', function (cURL\Event $event) {
    $response = $event->response;
    $content = $response->getContent();
    echo $content;
});

while ($request->socketPerform()) {
    // do anything else when the request is processed
}
Run Code Online (Sandbox Code Playgroud)


小智 5

function make_request($url, $waitResult=true){
    $cmi = curl_multi_init();

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    curl_multi_add_handle($cmi, $curl);

    $running = null;
    do {
        curl_multi_exec($cmi, $running);
        sleep(.1);
        if(!$waitResult)
        break;
    } while ($running > 0);
    curl_multi_remove_handle($cmi, $curl);
    if($waitResult){
        $curlInfos = curl_getinfo($curl);
        if((int) $curlInfos['http_code'] == 200){
            curl_multi_close($cmi);
            return curl_multi_getcontent($curl);
        }
    }
    curl_multi_close($cmi);
}
Run Code Online (Sandbox Code Playgroud)