首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP Curl 非同步 POST 遞歸陣列:主程式寫入主庫、子程式寫入測試庫解耦架構

     編輯:PHP 相關知識

業務場景

核心業務需同時寫入「線上正式庫」與「開發測試庫」。測試庫結構頻繁變更、不穩定,若同步寫入導致測試庫錯誤拋出異常,將回滾正式庫事務,造成嚴重可用性損失。

解耦方案:非同步 POST + register_shutdown_function

  1. 主程式 (a.php) 處理完核心邏輯,寫入正式庫並回應用戶。
  2. 註冊關閉函數,在請求結束、連線斷開後,以 Curl 非阻塞 POST 方式將資料陣列推送至 b.php。
  3. b.php 接收陣列,獨立連線寫入測試庫,失敗僅記錄日誌,不影響主流程。

主程式 a.php 關鍵代碼

<?php
// ... 核心業務邏輯,寫入正式 DB ...

$data = [
    'username' => '張三',
    'password' => 'secret',
    'ip' => $_SERVER['REMOTE_ADDR'],
    'action' => 'create_order',
    'payload' => $orderDetails
];

// 關閉函數:確保即使用戶關閉瀏覽器也會執行
register_shutdown_function('asyncPost', $data);

function asyncPost($data) {
    $curl = new Curl_Class();
    // 目標 b.php 內網地址,超時 3 秒,失敗不拋出
    $curl->post('https://10.0.0.5/b.php', $data, '', '', '', '', 3);
}

class Curl_Class {
    public function post($url, $fields, $userAgent='', $headers='', $user='', $pass='', $timeout=3) {
        return $this->execute('POST', $url, $fields, $userAgent, $headers, $user, $pass, $timeout);
    }

    private function execute($method, $url, $fields, $ua, $headers, $user, $pass, $timeout) {
        $ch = curl_init();
        if (!$ch) return false;

        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HEADER => false,
            CURLOPT_TIMEOUT => $timeout,
            CURLOPT_CONNECTTIMEOUT => 2,
            CURLOPT_NOSIGNAL => 1,          // 多執行緒環境下避免信號衝突
            CURLOPT_FORBID_REUSE => true,   // 短連線,用完即棄
            CURLOPT_FRESH_CONNECT => true,
        ]);

        if ($user) curl_setopt($ch, CURLOPT_USERPWD, "$user:$pass");
        if ($ua) curl_setopt($ch, CURLOPT_USERAGENT, $ua);
        if ($headers) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        if (strtoupper($method) === 'POST') {
            curl_setopt($ch, CURLOPT_POST, true);
            if (is_array($fields)) {
                $postFields = [];
                foreach ($fields as $k => $v) $postFields[] = "$k=" . urlencode($v);
                $fields = implode('&', $postFields);
            }
            curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
        }

        $ret = curl_exec($ch);
        if (curl_errno($ch)) {
            error_log("Curl asyncPost failed: " . curl_error($ch));
            curl_close($ch);
            return false;
        }
        curl_close($ch);
        return $ret;
    }
}
?>

接收端 b.php 還原陣列

<?php
ignore_user_abort(true); // 即使發起端斷開,仍完成處理
set_time_limit(30);

$raw = file_get_contents('php://input'); // 獲取原始 POST body
parse_str($raw, $data);                  // 還原為關聯陣列

// 現在 $data 結構與 a.php 完全一致,可直接寫入測試庫
// try { $testDb->insert('log', $data); } catch (Exception $e) { error_log($e->getMessage()); }
?>

關鍵優化點

  • 超時控制:CURLOPT_TIMEOUT=3 確保主程式不被掛起。
  • 錯誤隔離:Curl 失敗僅寫入錯誤日誌,不拋出異常。
  • 資料完整性:php://input + parse_str() 完美還原一維陣列;多維陣列建議 json_encode/decode。
  • 安全性:內網通訊、驗證來源 IP、簽名防篡改(HMAC)。
  • 擴展性:可改用消息佇列,實現更可靠的「至少一次」投遞。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved