我正在编写一个简单的REST服务,它响应来自客户端的请求。全部用PHP。
我担心的是,当我的服务器响应请求时,如果客户端发送回“ok”响应的速度太慢,最终可能会占用资源。
如何通过lib_curl发送POST请求,将其设置为不等待任何响应,而是在POST数据发送后立即退出?
这甚至可能吗?谢谢!
答案 0 :(得分:17)
您无法在未收到HTTP回答的情况下发送数据。 HTTP总是请求 - >响应。即使响应非常短(如简单的200没有文本),也需要有响应。每个HTTP套接字都会等待响应。
如果您不关心响应,可以向发出请求的服务器添加一个进程,然后只需将请求数据推送到它(就像正在运行的服务一样)后台,检查请求数据库,并且每当添加新条目时始终启动请求)。这样您就可以异步地发出请求,并且只要将该请求添加到堆栈就可以退出。
另外正如meouw所说,客户端不是你用php做的任何通信的一部分。 Php是一种服务器端语言,所以当客户端请求一个网页(php文件)时,服务器执行该文件(并且所有请求php文件的状态)然后将结果返回给客户端。
答案 1 :(得分:13)
这里:
ob_end_clean();
header("Connection: close\r\n");
header("Content-Encoding: none\r\n");
header("Content-Length: 1");
ignore_user_abort(true);
和卷曲:
curl_setopt($curl, CURLOPT_TIMEOUT_MS, 1);
curl_setopt($curl, CURLOPT_NOSIGNAL, 1);
答案 2 :(得分:8)
如果你真的不关心你的反应,你可能最好关注exec
wget命令。在其他一些答案中提到这一点,但这是一个非常简单的函数,通过这种方法发送_POST
包(这是异步的,需要1-2ms):
function wget_request($url, $post_array, $check_ssl=true) {
$cmd = "curl -X POST -H 'Content-Type: application/json'";
$cmd.= " -d '" . json_encode($post_array) . "' '" . $url . "'";
if (!$check_ssl){
$cmd.= "' --insecure"; // this can speed things up, though it's not secure
}
$cmd .= " > /dev/null 2>&1 &"; //just dismiss the response
exec($cmd, $output, $exit);
return $exit == 0;
}
致谢:功能改编自 https://segment.com/blog/how-to-make-async-requests-in-php/
答案 3 :(得分:2)
http://curl.haxx.se/mail/lib-2002-05/0090.html
libcurl没有异步接口。 你可以自己做 使用线程或使用 非阻塞的“多接口”即 libcurl提供。阅读多重 界面在这里:
http://curl.haxx.se/libcurl/c/libcurl-multi.html
多接口的PHP示例在这里:
http://www.phpied.com/simultaneuos-http-requests-in-php-with-curl/
答案 4 :(得分:1)
我从未尝试过这个,但将CURLOPT_TIMEOUT
设置为非常低的值可能会有所帮助。试试0
或0.1
。
但是,我不知道cURL和客户端将如何处理此问题,是否在建立连接时将主动取消连接,并且达到超时。你必须试试。如果你正在调用PHP脚本,也许ignore_user_abort()
可以确保你的脚本以任何一种方式运行。
答案 5 :(得分:0)
正如其他人所说,当您提出http请求时,您必须等待响应。
在PHP中,您可以使用exec函数发出请求。
答案 6 :(得分:0)
如果您有2个PHP服务器互相通信,例如服务器1 想要将JSON数据发送到服务器2 ,服务器2 正在做一些繁重的工作,并在收到请求后立即终止连接。数据,因此服务器1 不必等待结果。您可以这样做:
服务器1(客户端使用JSON数据创建POST请求):
使用CURL,不要使用 file_get_contents(),因为根据我的经验, file_get_contents()无法处理连接:close HTTP标头正确,并且没有终止连接。
$curl = curl_init('http://server2.com/');
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, ["Content-type: application/json"]);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode(['some data']));
$response = curl_exec($curl);
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
if ($status !== 200) {
exit("Failed with status {$status}, response {$response}, curl_error " . curl_error($curl) . ", curl_errno " . curl_errno($curl));
}
curl_close($curl);
echo $response;
服务器2:
使用了bubba-h57中的修改代码。
// Cause we are clever and don't want the rest of the script to be bound by a timeout.
// Set to zero so no time limit is imposed from here on out.
set_time_limit(0);
// Client disconnect should NOT abort our script execution
ignore_user_abort(true);
// Clean (erase) the output buffer and turn off output buffering
// in case there was anything up in there to begin with.
ob_end_clean();
// Turn on output buffering, because ... we just turned it off ...
// if it was on.
ob_start();
echo 'I received the data, closing connection now, bye.';
// Return the length of the output buffer
$size = ob_get_length();
// Send headers to tell the browser to close the connection
// Remember, the headers must be called prior to any actual
// input being sent via our flush(es) below.
header("Connection: close");
// Hack how to turn off mod deflate in Apache (gzip compression).
header("Content-Encoding: none");
header("Content-Length: {$size}");
// Set the HTTP response code
http_response_code(200);
// Flush (send) the output buffer and turn off output buffering
ob_end_flush();
// Flush (send) the output buffer
// This looks like overkill, but trust me. I know, you really don't need this
// unless you do need it, in which case, you will be glad you had it!
@ob_flush();
// Flush system output buffer
// I know, more over kill looking stuff, but this
// Flushes the system write buffers of PHP and whatever backend PHP is using
// (CGI, a web server, etc). This attempts to push current output all the way
// to the browser with a few caveats.
flush();
// Close current session.
session_write_close();
// Here, you can proceed with some heavy work.
echo "This won't be sent, the connection should be already closed";
答案 7 :(得分:0)
在 Laravel 中
use Illuminate\Support\Facades\Http;
...Some Code here
$prom = Http::timeout(1)->async()->post($URL_STRING, $ARRAY_DATA)->wait();
... Some more important code here
return "Request sent"; //OR whatever you need to return
这对我有用,因为我不需要总是知道回复。