使用PHP进行异步HTTP请求

Gavin [默认分类]

2011.07.20

使用PHP进行异步HTTP请求

使用JavaScript/Ajax可轻松实现异步HTTP请求,本文介绍使用PHP进行异步HTTP请求。所谓异步HTTP请求是指:HTTP协议基于TCP且是基于状态的,client和server建立连接后发送请求需要等到server处理结束并返回后才可以断开连接。某些情况下,client端只需要发出自己的请求即可,不需要知道server端的响应,这个时候即需要实现client端发出异步HTTP请求。另外,在长耗时应用中(请求的server端任务比较耗时,超过HTTP timeout时间甚至更长),也可以考虑使用异步HTTP请求出发该任务。关于长耗时应用也可以参考该文。


方法1:使用curl的CURLOPT_TIMEOUT或CURLOPT_TIMEOUT_MS

设置CURLOPT_TIMEOUT为最小值1,client端在等待1秒之后即返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$url = "http://www.yoursite.com/background-script.php";
$ref_url = "http://www.yoursite.com";
$data = array(
	"key1" => "value1",
	"key2" => "value2",
);
 
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
curl_setopt($ch, CURLOPT_REFERER, $ref_url);
 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
 
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);        
 
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
 
curl_exec($ch);
curl_close($ch);

如果是cURL 7.16.2 or higher and PHP 5.2.3 or above,可以设置Timeout时间为1 ms,实现立即返回,修改如上的curl_setopt($ch, CURLOPT_TIMEOUT, 1);为curl_setopt($ch, CURLOPT_TIMEOUT_MS, 1);。



方法2:使用socket修改HTTP header

使用socket连接到server上,发送raw HTTP header(注意设置Connection: Close),完成之后立即关闭socket不等待server做出响应再返回。

GET例子

需要请求的server url为http://example.com/Default.aspx,接受的参数为action=start,method为GET,需要携带的cookies为ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah。(这些信息都可以使用HttpWatch分析得到)。

例如HttpWatch的分析的client端的HTTP请求为:

 查看代码 PLAIN
1
2
3
4
5
6
7
GET /Default.aspx?action=start HTTP/1.1
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)
Accept-Encoding: gzip, deflate
Host: example.com
Connection: Keep-Alive
Cookie: ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah

修改为异步HTTP请求:

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
<?php
 
$host = "example.com";
$path = "/Default.aspx?action=start";
$cookie = "ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah";
 
$start = microtime(true);
 
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if (!$fp) {
   print "$errstr ($errno)<br />\n";
   exit;
}
$out = "GET ".$path." HTTP/1.1\r\n";
$out .= "Host: ".$host."\r\n";          //需要注意Host不能包括`http://`,仅可以使用`example.com`
$out .= "Connection: Close\r\n";
$out .= "Cookie: ".$cookie."\r\n\r\n";
 
fwrite($fp, $out);  //将请求写入socket
 
/*
//也可以选择获取server端的响应
while (!feof($fp)) {
    echo fgets($fp, 128);
}
*/
 
//如果不等待server端响应直接关闭socket即可
fclose($fp);
 
$cost = microtime(true) - $start; 
print "\n".$cost."\n";
exit;



POST例子

需要请求的server url为http://example.com/Login.aspx,接受的参数为username=my-username&password=my-password,method为POST,需要携带的cookies为ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah。(这些信息都可以使用HttpWatch分析得到)。

例如HttpWatch的分析的client端的HTTP请求为:

 查看代码 PLAIN
1
2
3
4
5
6
7
8
9
10
11
POST /Login.aspx HTTP/1.1
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate
Host: example.com
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah
 
username=my-username&password=my-password

修改为异步HTTP请求:

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
<?php
 
$host = "example.com";
$path = "/Login.aspx";
$cookie = "ASP.NET_SessionId=zfyaimqgtt1bfiewq0najgah";
$params = "username=my-username&password=my-password";
 
$start = microtime(true);
 
$fp = fsockopen($host, 80, $errno, $errstr, 30);
if (!$fp) {
   print "$errstr ($errno)<br />\n";
   exit;
}
$out = "POST ".$path." HTTP/1.1\r\n";
$out .= "Host: ".$host."\r\n";
$out .= "Connection: Close\r\n";
$out .= "Cookie: ".$cookie."\r\n\r\n";
$out .= $params;
 
fwrite($fp, $out);  
 
/*
//也可以选择获取server端的响应
while (!feof($fp)) {
    echo fgets($fp, 128);
}
*/
 
//如果不等待server端响应直接关闭socket即可
fclose($fp);
 
$cost = microtime(true) - $start; 
print "\n".$cost."\n";
exit;



参考:
1、http://www.paul-norman.co.uk/2009/06/asynchronous-curl-requests/
2、http://petewarden.typepad.com/searchbrowser/2008/06/how-to-post-an.html
3、http://stackoverflow.com/questions/962915/how-do-i-make-an-asynchronous-get-request-in-php


5 条评论

  1. 不错不错,支持支持!

  2. 持之以恒干革命的硬道理,至于你信不信,反正我信了73

  3. 哈哈,好hit呐。。

  4. 帮博主顶一下。

  5. 最近怎么感觉 博客更新慢了哦

评论

输入后可按 Ctrl+Enter 提交评论.