PHP实现无需等待响应的HTTPS POST请求(Fire and Forget)失效问题
PHP实现无依赖的Fire-and-Forget POST请求(支持HTTPS)
原代码在HTTP模式下正常,但HTTPS模式失效,核心原因是fsockopen连接HTTPS端口时未建立TLS加密通道,直接发送明文HTTP请求会被服务器拒绝。以下是修复后的完整实现:
修复后的代码
private function sendRequestAndForget(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; $isHttps = ($parts['scheme'] === 'https'); $port = $parts['port'] ?? ($isHttps ? 443 : 80); $path = $parts['path'] ?? '/'; $query = $parts['query'] ?? ''; parse_str($query, $queryParts); if ($host === null) throw new Exception('Unknown host'); // 建立TLS加密连接(HTTPS核心修复) $socketContext = stream_context_create([ 'ssl' => [ 'verify_peer' => false, // 生产环境建议设为true并配置CA证书 'verify_peer_name' => false, ] ]); $connectionString = ($isHttps ? 'tls://' : '') . $host . ':' . $port; $connection = stream_socket_client( $connectionString, $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $socketContext ); if ($connection === false) throw new Exception('Unable to connect to ' . $host . ": $errstr ($errno)"); $method = strtoupper($method); if (!in_array($method, ['POST', 'PUT', 'PATCH'], true)) { $queryParts = $params + $queryParts; $params = []; } // 构建HTTP请求 $request = $method . ' ' . $path; if ($queryParts) { $request .= '?' . http_build_query($queryParts); } $request .= ' HTTP/1.1' . "\r\n"; $request .= 'Host: ' . $host . "\r\n"; $request .= 'Connection: Close' . "\r\n"; $body = json_encode($params); if ($body) { $request .= 'Content-Type: application/json' . "\r\n"; $request .= 'Content-Length: ' . strlen($body) . "\r\n"; } $request .= "\r\n"; // HTTP头部结束标记 $request .= $body; // 发送后立即关闭连接,实现真正的"发后即忘" fwrite($connection, $request); stream_set_blocking($connection, false); // 非阻塞模式避免等待响应 fclose($connection); }
关键修改说明
TLS加密处理:
- 用
stream_socket_client替代fsockopen,通过tls://前缀强制HTTPS连接使用加密通道 - SSL上下文配置:生产环境需开启
verify_peer和verify_peer_name,并指定CA证书路径以避免安全风险
- 用
确保无等待逻辑:
- 添加
stream_set_blocking($connection, false),防止写入或关闭连接时阻塞等待服务器响应 - 发送请求后立即关闭连接,不读取任何服务器返回内容
- 添加
HTTP规范修正:
- 调整
Connection: Close位置,确保服务器正确识别连接关闭指令 - 严格遵循HTTP协议的头部结束空行格式
- 调整
测试验证
调用该方法后,你的测试脚本中的sleep(5000)不会阻塞发起请求的脚本,发起方会立即返回,测试脚本将在后台独立执行。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

