在 DNS 輪詢等負載均衡架構中,同一域名可能解析到多個 IP 地址。例如 blog.kcoffee.net 對應 72.249.146.213、.214、.215 三台服務器。若直接使用 file_get_contents 訪問該域名,請求會被負載均衡器隨機分發,無法保證依次訪問每台服務器的特定接口(如 abc.php)以檢查傳輸狀態。
若改用直接訪問 IP(如 https://72.249.146.213/abc.php),在服務器配置了多個虛擬主機時,Web Server 無法識別請求的目標主機,導致訪問失敗。修改本地 hosts 文件也無法實現一域名多 IP 映射。
利用 HTTP 協議特性:在建立 TCP 連接到目標 IP 後,於 HTTP Request Header 中手動指定 Host 欄位為目標域名。這樣 Web Server 即可根據 Host 標頭正確路由到對應的虛擬主機。
<?php
/**
* 同域名多 IP 環境下,獲取指定服務器的遠程網頁內容
* @param string $ip 目標服務器 IP 地址
* @param string $host 目標域名(Host 標頭值)
* @param string $url 請求路徑(不含域名,如 /abc.php)
* @return string|false 成功返回頁面內容,失敗返回 false
*/
function HttpVisit($ip, $host, $url) {
$errno = $errstr = '';
// 建立 TCP 連接,超時 90 秒
$fp = fsockopen($ip, 80, $errno, $errstr, 90);
if (!$fp) {
return false;
}
// 構造 HTTP/1.1 GET 請求,關鍵在於 Host 標頭
$out = "GET {$url} HTTP/1.1\r\n";
$out .= "Host: {$host}\r\n";
$out .= "Connection: close\r\n\r\n";
fputs($fp, $out);
// 讀取完整回應
$response = '';
while ($line = fread($fp, 4096)) {
$response .= $line;
}
fclose($fp);
// 去除 HTTP 標頭,僅保留 Body
$pos = strpos($response, "\r\n\r\n");
if ($pos !== false) {
$response = substr($response, $pos + 4);
}
return $response;
}
// 調用示例:依次檢查三台服務器狀態
$server_info1 = HttpVisit("72.249.146.213", "blog.s135.com", "/abc.php");
$server_info2 = HttpVisit("72.249.146.214", "blog.s135.com", "/abc.php");
$server_info3 = HttpVisit("72.249.146.215", "blog.s135.com", "/abc.php");
?>