PHP Fire and Forget POST 请求

Posted

技术标签:

【中文标题】PHP Fire and Forget POST 请求【英文标题】:PHP Fire and Forget POST Request 【发布时间】:2013-01-13 07:05:29 【问题描述】:

我正在尝试在 php 中创建一个“一劳永逸”的方法,以便我可以将 POST 数据发送到 Web 服务器而无需等待响应。我读到这可以通过使用CURL 来实现,如下代码所示:

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_fields);
curl_exec($ch);
curl_close($ch);

但是我不认为它按我预期的那样工作。例如,如果我发送请求的 URL 有错误,它也会导致我的脚本抛出错误。如果它着火了然后忘记了,我希望这不会发生。

谁能告诉我我做错了什么或提供替代建议。我在本地使用 Windows,在开发、暂存和生产环境中使用 Linux。

更新

我在这里找到了替代解决方案:http://blog.markturansky.com/archives/205

我已将其清理为以下代码:

function curl_post_async($url, $params = array())

    // create POST string   
    $post_params = array();
    foreach ($params as $key => &$val) 
    
        $post_params[] = $key . '=' . urlencode($val);
    
    $post_string = implode('&', $post_params);

    // get URL segments
    $parts = parse_url($url);

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

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

    // send output to $url handle
    fwrite($fp, $output);
    fclose($fp);

这个似乎更适合我。

这是一个有效的解决方案吗?

【问题讨论】:

您在这里所做的只是发送请求并关闭连接。所以它不像你想象的那样异步。您可以分叉该进程,或打开一个新进程。 PHP 不具备多任务能力。 您使用的是网络服务器还是 CLI? 这是使用网络服务器。 您自己托管,您是否有权访问 system() 命令? 我们使用亚马逊网络服务自托管,所以我们控制所有机器实例等,并可以根据我们的需要设置服务器。如果我无权访问system(),我可以请求启用它。 【参考方案1】:

是的,如果您不关心所调用 URL 的响应,则可以使用套接字。这是因为套接字连接可以在发送请求后直接终止而无需等待,而这正是您所追求的 - 即发即弃。

两个注意事项:

    它不再是一个 cURL 请求,因此值得重命名该函数。 :)

    绝对值得检查是否可以打开套接字,以防止脚本稍后在 if 失败时抱怨:

    $fp = fsockopen($parts['host'], $port, $errno, $errstr, 30);
    
    if ( ! $fp)
    
       return FALSE;
    
    

值得链接到您现在使用的 fsocket() 脚本的原始源代码:http://w-shadow.com/blog/2007/10/16/how-to-run-a-php-script-in-the-background/

【讨论】:

fwrite($fp, $data); 之前我见过stream_set_blocking($fp, 0); 的地方难道不是这里也有必要吗?【参考方案2】:

这是 diggersworld 代码的清理版本,它还处理其他 HTTP 方法,然后是 POST,并在函数失败时抛出有意义的异常。

/**
 * Send a HTTP request, but do not wait for the response
 *
 * @param string $method The HTTP method
 * @param string $url The url (including query string)
 * @param array $params Added to the URL or request body depending on method
 */
public function sendRequest(string $method, string $url, array $params = []): void

    $parts = parse_url($url);
    if ($parts === false)
        throw new Exception('Unable to parse URL');
    $host = $parts['host'] ?? null;
    $port = $parts['port'] ?? 80;
    $path = $parts['path'] ?? '/';
    $query = $parts['query'] ?? '';
    parse_str($query, $queryParts);

    if ($host === null)
        throw new Exception('Unknown host');
    $connection = fsockopen($host, $port, $errno, $errstr, 30);
    if ($connection === false)
        throw new Exception('Unable to connect to ' . $host);
    $method = strtoupper($method);

    if (!in_array($method, ['POST', 'PUT', 'PATCH'], true)) 
        $queryParts = $params + $queryParts;
        $params = [];
    

    // Build request
    $request  = $method . ' ' . $path;
    if ($queryParts) 
        $request .= '?' . http_build_query($queryParts);
    
    $request .= ' HTTP/1.1' . "\r\n";
    $request .= 'Host: ' . $host . "\r\n";

    $body = http_build_query($params);
    if ($body) 
        $request .= 'Content-Type: application/x-www-form-urlencoded' . "\r\n";
        $request .= 'Content-Length: ' . strlen($body) . "\r\n";
    
    $request .= 'Connection: Close' . "\r\n\r\n";
    $request .= $body;

    // Send request to server
    fwrite($connection, $request);
    fclose($connection);

【讨论】:

以上是关于PHP Fire and Forget POST 请求的主要内容,如果未能解决你的问题,请参考以下文章

C# Fire and Forget 任务和丢弃

OwinCommunicationListener 中托管的 Async Web Api 中的 Fire and Forget 方法

Cordova + ngrx/effect fire and forget long running 方法冻结 UI

如何像 WCF 一样实现 Asp.net MVC One Way/Fire And Forget 调用?

Asp.net core web Api Fire and Forget BG task

Python3.7中的Fire、Forget和返回值