如何在 PHP 中发出异步 GET 请求?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/962915/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I make an asynchronous GET request in PHP?
提问by Abs
I wish to make a simple GET request to another script on a different server. How do I do this?
我希望向不同服务器上的另一个脚本发出简单的 GET 请求。我该怎么做呢?
In one case, I just need to request an external script without the need for any output.
在一种情况下,我只需要请求一个外部脚本而不需要任何输出。
make_request('http://www.externalsite.com/script1.php?variable=45'); //example usage
In the second case, I need to get the text output.
在第二种情况下,我需要获取文本输出。
$output = make_request('http://www.externalsite.com/script2.php?variable=45');
echo $output; //string output
To be honest, I do not want to mess around with CURL as this isn't really the job of CURL. I also do not want to make use of http_get as I do not have the PECL extensions.
老实说,我不想弄乱 CURL,因为这不是 CURL 真正的工作。我也不想使用 http_get,因为我没有 PECL 扩展。
Would fsockopen work? If so, how do I do this without reading in the contents of the file? Is there no other way?
fsockopen 会工作吗?如果是这样,如何在不读取文件内容的情况下执行此操作?没有其他办法了吗?
Thanks all
谢谢大家
Update
更新
I should of added, in the first case, I do not want to wait for the script to return anything. As I understand file_get_contents() will wait for the page to load fully etc?
我应该补充说,在第一种情况下,我不想等待脚本返回任何内容。据我了解 file_get_contents() 将等待页面完全加载等?
采纳答案by Marquis Wang
file_get_contentswill do what you want
file_get_contents会做你想做的
$output = file_get_contents('http://www.example.com/');
echo $output;
Edit: One way to fire off a GET request and return immediately.
编辑:触发 GET 请求并立即返回的一种方法。
Quoted from http://petewarden.typepad.com/searchbrowser/2008/06/how-to-post-an.html
引自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);
}
What this does is open a socket, fire off a get request, and immediately close the socket and return.
它的作用是打开一个套接字,发出一个 get 请求,然后立即关闭套接字并返回。
回答by catgofire
This is how to make Marquis' answer work with both POST and GET requests:
这是如何使 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);
}
回答by dbr
Regarding your update, about not wanting to wait for the full page to load - I think a HTTP HEADrequest is what you're looking for..
关于您的更新,关于不想等待整个页面加载 - 我认为 HTTPHEAD请求是您正在寻找的......
get_headersshould do this - I think it only requests the headers, so will not be sent the full page content.
get_headers应该这样做 - 我认为它只请求标题,所以不会发送整页内容。
"PHP / Curl: HEAD Request takes a long time on some sites"describes how to do a HEADrequest using PHP/Curl
“PHP / Curl:HEAD 请求在某些站点上需要很长时间”描述了如何HEAD使用 PHP/Curl执行请求
If you want to trigger the request, and not hold up the script at all, there are a few ways, of varying complexities..
如果您想触发请求,而根本不想阻止脚本,有几种方法,复杂程度各不相同。
- Execute the HTTP request as a background process, php execute a background process- basically you would execute something like
"wget -O /dev/null $carefully_escaped_url"- this will be platform specific, and you have to be reallycareful about escaping parameters to the command - Executing a PHP script in the background- basically the same as the UNIX process method, but executing a PHP script rather than a shell command
- Have a "job queue", using a database (or something like beanstalkdwhich is likely overkill). You add a URL to the queue, and a background process or cron-job routinely checks for new jobs and performs requests on the URL
- 作为后台进程执行 HTTP 请求,php 执行后台进程- 基本上你会执行类似的东西
"wget -O /dev/null $carefully_escaped_url"- 这将是特定于平台的,你必须非常小心将参数转义到命令 - 在后台执行PHP脚本——与UNIX进程方法基本相同,但执行的是PHP脚本而不是shell命令
- 有一个“作业队列”,使用数据库(或像beanstalkd这样可能有点矫枉过正的东西)。您向队列添加一个 URL,后台进程或 cron-job 会例行检查新作业并对 URL 执行请求
回答by Alan Storm
You don't. While PHP offers lots of ways to call a URL, it doesn't offer out of the box support for doing any kind of asynchronous/threaded processing per request/execution cycle. Any method of sending a request for a URL (or a SQL statement, or a etc.) is going to wait for somekind of response. You'll need some kind of secondary system running on the local machine to achieve this (google around for "php job queue")
你没有。虽然 PHP 提供了许多调用 URL 的方法,但它不提供对每个请求/执行周期进行任何类型的异步/线程处理的开箱即用支持。任何发送 URL 请求(或 SQL 语句或等)的方法都将等待某种响应。你需要在本地机器上运行某种辅助系统来实现这一点(谷歌搜索“php job queue”)
回答by stil
I would recommend you well tested PHP library: curl-easy
我会推荐你经过充分测试的 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
}
回答by Stranger
If you are using Linux environment then you can use the PHP's exec command to invoke the linux curl. Here is a sample code, which will make a Asynchronous HTTP post.
如果您使用的是 Linux 环境,那么您可以使用 PHP 的 exec 命令来调用 linux curl。这是一个示例代码,它将生成一个异步 HTTP 帖子。
function _async_http_post($url, $json_string) {
$run = "curl -X POST -H 'Content-Type: application/json'";
$run.= " -d '" .$json_string. "' " . "'" . $url . "'";
$run.= " > /dev/null 2>&1 &";
exec($run, $output, $exit);
return $exit == 0;
}
This code does not need any extra PHP libs and it can complete the http post in less than 10 milliseconds.
这段代码不需要任何额外的 PHP 库,它可以在不到 10 毫秒的时间内完成 http 发布。
回答by amez
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);
}
回答by Darryl Hein
Interesting problem. I'm guessing you just want to trigger some process or action on the other server, but don't care what the results are and want your script to continue. There is probably something in cURL that can make this happen, but you may want to consider using exec()to run another script on the server that does the call if cURL can't do it. (Typically people want the results of the script call so I'm not sure if PHP has the ability to just trigger the process.) With exec()you could run a wgetor even another PHP script that makes the request with file_get_conents().
有趣的问题。我猜你只是想在另一台服务器上触发一些进程或操作,但不关心结果是什么,并希望你的脚本继续。cURL 中可能有一些东西可以实现这一点,但是exec()如果 cURL 无法执行调用,您可能需要考虑使用在执行调用的服务器上运行另一个脚本。(通常人们想要脚本调用的结果,所以我不确定 PHP 是否有能力触发该过程。)exec()您可以运行一个wget甚至另一个 PHP 脚本,该脚本使用file_get_conents().
回答by mra214
You'd better consider using Message Queues instead of advised methods. I'm sure this will be better solution, although it requires a little more job than just sending a request.
您最好考虑使用消息队列而不是建议的方法。我相信这将是更好的解决方案,尽管它需要的工作不仅仅是发送请求。
回答by user1031143
let me show you my way :)
让我告诉你我的方式:)
needs nodejs installed on the server
需要在服务器上安装 nodejs
(my server sends 1000 https get request takes only 2 seconds)
(我的服务器发送 1000 个 https get 请求只需要 2 秒)
url.php :
网址.php :
<?
$urls = array_fill(0, 100, 'http://google.com/blank.html');
function execinbackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
fwite(fopen("urls.txt","w"),implode("\n",$urls);
execinbackground("nodejs urlscript.js urls.txt");
// { do your work while get requests being executed.. }
?>
urlscript.js >
urlscript.js >
var https = require('https');
var url = require('url');
var http = require('http');
var fs = require('fs');
var dosya = process.argv[2];
var logdosya = 'log.txt';
var count=0;
http.globalAgent.maxSockets = 300;
https.globalAgent.maxSockets = 300;
setTimeout(timeout,100000); // maximum execution time (in ms)
function trim(string) {
return string.replace(/^\s*|\s*$/g, '')
}
fs.readFile(process.argv[2], 'utf8', function (err, data) {
if (err) {
throw err;
}
parcala(data);
});
function parcala(data) {
var data = data.split("\n");
count=''+data.length+'-'+data[1];
data.forEach(function (d) {
req(trim(d));
});
/*
fs.unlink(dosya, function d() {
console.log('<%s> file deleted', dosya);
});
*/
}
function req(link) {
var linkinfo = url.parse(link);
if (linkinfo.protocol == 'https:') {
var options = {
host: linkinfo.host,
port: 443,
path: linkinfo.path,
method: 'GET'
};
https.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
} else {
var options = {
host: linkinfo.host,
port: 80,
path: linkinfo.path,
method: 'GET'
};
http.get(options, function(res) {res.on('data', function(d) {});}).on('error', function(e) {console.error(e);});
}
}
process.on('exit', onExit);
function onExit() {
log();
}
function timeout()
{
console.log("i am too far gone");process.exit();
}
function log()
{
var fd = fs.openSync(logdosya, 'a+');
fs.writeSync(fd, dosya + '-'+count+'\n');
fs.closeSync(fd);
}

