如何高效使用file_get_contents()访问同一域名下的多个URL?
嘿,这个问题我太熟了——循环调用file_get_contents()串行请求确实会在域名解析、TCP握手这些环节浪费大量时间,尤其是同一域名下的多页面,很多重复开销完全可以省掉。下面给你拆解几个实用的提速思路,重点覆盖你提到的避免重复域名解析的需求:
提前解析域名并复用IP:默认每次
file_get_contents()都会重新发起DNS解析,你可以先用gethostbyname()提前把域名解析成IP,后续请求直接用IP访问,同时在请求头里指定Host字段(保证服务器能正确识别站点),这样整个循环里只做一次DNS解析,彻底省掉重复解析的开销。示例代码:$domain = 'your-target-domain.com'; $resolvedIp = gethostbyname($domain); // 提前完成一次域名解析 $requestHeaders = ['Host: ' . $domain]; foreach ($yourPageUrls as $url) { // 替换URL中的域名为已解析的IP $ipBasedUrl = str_replace($domain, $resolvedIp, $url); $context = stream_context_create([ 'http' => [ 'header' => implode("\r\n", $requestHeaders), 'method' => 'GET' ] ]); $pageContent = file_get_contents($ipBasedUrl, false, $context); // 处理采集到的内容... }开启HTTP持久连接(Keep-Alive):默认
file_get_contents()可能不会自动复用TCP连接,你可以通过上下文配置开启Keep-Alive,这样同一个TCP连接可以发送多个请求,既省去了每次的TCP握手和慢启动时间,也间接减少了DNS解析的触发(因为连接复用后不需要重新解析域名建立新连接)。示例:$persistContext = stream_context_create([ 'http' => [ 'header' => "Connection: Keep-Alive\r\nHost: your-target-domain.com", 'keep_alive' => true ] ]); foreach ($yourPageUrls as $url) { $pageContent = file_get_contents($url, false, $persistContext); // 处理采集到的内容... }注意要确保目标服务器支持Keep-Alive(大部分现代服务器都默认支持),这样循环内的请求会复用同一个TCP连接,速度提升非常明显。
改用并行请求替代串行循环:串行请求是等一个请求完成再发下一个,并行可以同时发起多个请求,直接把总耗时从「所有请求时间之和」降到「最慢的单个请求时间」。PHP里可以用
curl_multi_*系列函数实现,同时还能配置DNS缓存进一步减少解析开销。示例:$targetUrls = ['https://your-target-domain.com/page1', 'https://your-target-domain.com/page2', ...]; $multiHandle = curl_multi_init(); $curlHandles = []; // 初始化所有curl请求句柄 foreach ($targetUrls as $url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, ['Connection: Keep-Alive']); curl_setopt($ch, CURLOPT_DNS_CACHE_TIMEOUT, 3600); // 缓存DNS解析结果1小时 curl_multi_add_handle($multiHandle, $ch); $curlHandles[] = $ch; } // 执行并行请求 $runningCount = null; do { curl_multi_exec($multiHandle, $runningCount); curl_multi_select($multiHandle); } while ($runningCount > 0); // 收集并处理结果 $collectedContents = []; foreach ($curlHandles as $ch) { $collectedContents[] = curl_multi_getcontent($ch); curl_multi_remove_handle($multiHandle, $ch); curl_close($ch); } curl_multi_close($multiHandle);全局启用DNS缓存:你也可以通过PHP配置延长DNS缓存时间,让所有HTTP请求自动复用解析结果,无需手动替换IP。可以在php.ini里设置,或者用
ini_set()动态配置:ini_set('dns_cache_expire', 3600); // 有效DNS结果缓存1小时 ini_set('dns_cache_neg_expire', 300); // 无效DNS结果缓存5分钟这个是全局配置,适合所有HTTP请求场景,能从根源减少重复解析的次数。
总的来说,最有效的组合是提前解析域名+开启Keep-Alive持久连接+并行请求,这三个点结合起来,能把同一域名下多页面采集的速度提升好几倍。如果你的采集量很大,甚至可以考虑用Swoole这类异步框架来做更高性能的并发请求。
内容的提问来源于stack exchange,提问作者Vineet Sharma

