php 发送 POST 请求而不等待响应?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2190854/
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
Sending POST Requests without waiting for response?
提问by Gotys
I am writing a simple REST service, which responds to requests from clients. All in PHP.
我正在编写一个简单的 REST 服务,它响应来自客户端的请求。全部在 PHP 中。
My concern is, that when my server responds to a request, it could end up tying up resources if the client side is too slow in sending back "ok" response.
我担心的是,当我的服务器响应请求时,如果客户端发送回“ok”响应太慢,它最终可能会占用资源。
How do I send a POST request via lib_curl setting it to not wait for any responses, but rather quit immidiately after the POST data have been sent?
如何通过 lib_curl 发送 POST 请求,将其设置为不等待任何响应,而是在发送 POST 数据后立即退出?
Is this even possible? Thank you !
这甚至可能吗?谢谢 !
采纳答案by poke
You cannot just send data without receiving an answer with HTTP. HTTP always goes request -> response. Even if the response is just very short (like a simple 200 with no text), there needs to be a response. And every HTTP socket will wait for that response.
您不能在没有收到 HTTP 响应的情况下发送数据。HTTP 总是请求 -> 响应。即使回复很短(比如没有文字的简单 200),也需要有回复。每个 HTTP 套接字都将等待该响应。
If you don't care about the response, you could add a process to the server that makes your requests, and you just pushyour request data to it (like a service that is running in the background, checking a request database, and always starting the request whenever a new entry was added). That way you would make the request asynchronously and could quit as soon as you added that request to the stack.
如果您不关心响应,则可以向发出请求的服务器添加一个进程,然后将请求数据推送给它(例如在后台运行的服务,检查请求数据库,并且始终每当添加新条目时启动请求)。这样您就可以异步发出请求,并且可以在将该请求添加到堆栈后立即退出。
Also as meouw said, the client is not part of any communication you are doing with php. Php is a server-side language, so when the client requests a webpage (the php file), the serverexecutes that file (and does all requests the php file states) and then returns the result to the client.
同样正如meouw所说,客户端不是您与php进行的任何通信的一部分。Php 是一种服务器端语言,因此当客户端请求一个网页(php 文件)时,服务器会执行该文件(并执行 php 文件状态的所有请求),然后将结果返回给客户端。
回答by Kamil D?browski
This solutions is for software minimal recevied package to continue script. If you want don't care about respond and have access to exec than use exec and call script in background. First Recevier File:
此解决方案用于软件最小接收包以继续脚本。如果您不想在乎响应并有权访问 exec,则不要使用 exec 并在后台调用脚本。第一个接收器文件:
recevier.php
接收者.php
ignore_user_abort(true); //continue script if connetions become close by webbrowser(client) within working script
ob_end_clean(); // this 4 lines just extra sending to web about close connect it just in case
header("Connection: close\r\n"); //send to website close connect
header("Content-Encoding: none\r\n");
header("Content-Length: 1"); //
fastcgi_finish_request(); //close nginx,apache connect to php-fpm (php working but nginx or apache stop communication with php)
//continue scripting
// ...DO HERE WHAT YOU WANT ...
//check test with your mongo or mysql to sure php still keep connection with db
FRONTGROUND by PHP request to HTTP:this solution is better than background and you need wait only 1ms
PHP 对 HTTP 请求的 FRONTGROUND:此解决方案比后台更好,您只需要等待 1 毫秒
sender.php:
发件人.php:
curl_setopt($curl, CURLOPT_TIMEOUT_MS, 1); //HERE MAGIC (We wait only 1ms on connection) Script waiting but (processing of send package to $curl is continue up to successful) so after 1ms we continue scripting and in background php continue already package to destiny. This is like apple on tree, we cut and go, but apple still fallow to destiny but we don't care what happened when fall down :)
curl_setopt($curl, CURLOPT_NOSIGNAL, 1); // i'dont know just it works together read manual ;)
--------- Check next answer to complete solution ------------
---------检查下一个答案以完成解决方案------------
BACKGROUND By Server Request to HTTP: This will execute $cmd in the background (no cmd window) without PHP waiting for it to finish, on both Windows and Unix. @source https://www.php.net/manual/en/function.exec.php
后台通过服务器请求 HTTP:这将在后台执行 $cmd (没有 cmd 窗口),而无需 PHP 等待它完成,在 Windows 和 Unix 上。@source https://www.php.net/manual/en/function.exec.php
<?php
function execInBackground($cmd) {
if (substr(php_uname(), 0, 7) == "Windows"){
pclose(popen("start /B ". $cmd, "r"));
}
else {
exec($cmd . " > /dev/null &");
}
}
?>
回答by Ben D
If you really don't care about the response you're probably best off exec-ing a wget command. This is mentioned in passing in some of the other answers, but here's a super easy function for sending a _POSTpackage via this approach (which is asynchronous and takes 1-2ms):
如果您真的不关心响应,您可能最好exec使用 wget 命令。在传递其他一些答案时提到了这一点,但这里有一个_POST通过这种方法发送包的超级简单的功能(它是异步的,需要 1-2 毫秒):
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;
}
Credits: Function was adapted from https://segment.com/blog/how-to-make-async-requests-in-php/
积分:功能改编自 https://segment.com/blog/how-to-make-async-requests-in-php/
回答by Tahir Akhtar
http://curl.haxx.se/mail/lib-2002-05/0090.html
http://curl.haxx.se/mail/lib-2002-05/0090.html
libcurl has no asynchronous interface. You can do that yourself either by using threads or by using the non-blocking "multi interface" that libcurl offers. Read up on the multi interface here:
libcurl 没有异步接口。您可以通过使用线程或使用 libcurl 提供的非阻塞“多接口”来自己完成。在此处阅读多界面:
http://curl.haxx.se/libcurl/c/libcurl-multi.html
http://curl.haxx.se/libcurl/c/libcurl-multi.html
PHP example of multi interface is here:
多界面的PHP示例在这里:
http://www.phpied.com/simultaneuos-http-requests-in-php-with-curl/
http://www.phpied.com/simultaneuos-http-requests-in-php-with-curl/
回答by OndrejC
If you have 2 PHP servers communicating with each other, e.g. server 1wants to send JSON data to a server 2, the server 2is doing some heavy work and terminates the connection right after it receives the data so the server 1doesn't have to wait for the result. You can do it like this:
如果您有 2 个 PHP 服务器相互通信,例如服务器 1想要将 JSON 数据发送到服务器 2,则服务器 2正在做一些繁重的工作并在收到数据后立即终止连接,因此服务器 1没有等待结果。你可以这样做:
Server 1 (client creating POST request with JSON data):
服务器 1(客户端使用 JSON 数据创建 POST 请求):
Use CURL, don't use file_get_contents()because in my experience, file_get_contents()doesn't handle Connection: closeHTTP header correctly and doesn't terminate the connection as it should.
使用 CURL,不要使用file_get_contents(),因为根据我的经验,file_get_contents()不能正确处理Connection: closeHTTP 标头,也不会按应有的方式终止连接。
$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;
Server 2:
服务器 2:
Modified code from bubba-h57used.
使用了来自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";
回答by Pekka
I have never tried this, but setting the CURLOPT_TIMEOUTto a very low value might do the trick. Try 0or 0.1.
我从未尝试过,但将 设置 CURLOPT_TIMEOUT为非常低的值可能会奏效。尝试0或0.1。
However, I don't know how cURL and the client will behave with this, whether the connection will be actively cancelled when the connection is already established, and the timeout is reached. You would have to try out. If you're calling PHP scripts, maybe ignore_user_abort()can make sure your scripts run through either way.
但是,我不知道cURL和客户端会如何处理这个,当连接已经建立时是否会主动取消连接,并达到超时。你将不得不尝试。如果您正在调用 PHP 脚本,也许ignore_user_abort()可以确保您的脚本通过任何一种方式运行。
回答by JesusIniesta
As other people says when you make a http request you have to wait the response.
正如其他人所说,当您发出 http 请求时,您必须等待响应。
In PHP what you can do is make the request using the exec function.
在 PHP 中,您可以做的是使用 exec 函数发出请求。
Check this link: php exec command (or similar) to not wait for result
检查此链接:php exec 命令(或类似命令)不等待结果

