优化PHP使用file_get_contents请求多JSON接口的慢加载问题
PHP多HTTP请求场景加载速度优化方案
你当前性能瓶颈来自循环内串行发起10次独立HTTP请求,单次file_get_contents请求本身存在DNS查询、TCP握手、TLS校验(如果是HTTPS)的固定开销,串行执行时总耗时是10次请求耗时的累加,自然会导致页面加载速度大幅下降。以下是可落地的优化方案:
1. 改用cURL并发请求(优先级最高)
使用PHP的curl_multi_*系列函数并行发起所有HTTP请求,总耗时仅等于10次请求中最慢的单次请求耗时,通常可以把这部分耗时压缩到原来的1/3~1/10。
示例代码:
<?php $site = file_get_contents('website.com/content.json'); $obj = json_decode($site, true); $idList = []; for ($i = 0; $i <= 9; $i++) { $idList[] = $obj[$i]['id']; } // 初始化curl多句柄 $mh = curl_multi_init(); $chList = []; $infos = []; // 批量添加请求 foreach ($idList as $id) { $ch = curl_init("website.com/info/" . $id . ".json"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 2); curl_setopt($ch, CURLOPT_TIMEOUT, 5); curl_multi_add_handle($mh, $ch); $chList[$id] = $ch; } // 执行并发请求 $running = null; do { curl_multi_exec($mh, $running); curl_multi_select($mh); } while ($running > 0); // 收集返回结果 foreach ($idList as $id) { $content = curl_multi_getcontent($chList[$id]); $infos[$id] = json_decode($content, true); curl_multi_remove_handle($mh, $chList[$id]); curl_close($chList[$id]); } curl_multi_close($mh); // 渲染输出 for ($i = 0; $i <= 9; $i++) { $id = $obj[$i]['id']; echo '<div class="result-' . $id . '">'; echo $infos[$id]['content'] ?? ''; echo '</div>'; } ?>
2. 增加请求结果缓存
如果对应id的info数据不是实时性要求极高的内容,添加缓存层可以避免重复发起请求,是性能收益最高的方案:
- 缓存介质可以选择APCu(进程级内存缓存)、Redis(分布式缓存)、本地文件缓存,根据你的部署环境选择即可
- 缓存过期时间可以根据业务更新频率设置,通常设置5~60分钟即可覆盖绝大多数用户访问场景
简单本地文件缓存示例:
// 获取info的封装函数 function getInfoById($id) { $cachePath = __DIR__ . '/cache/info_' . $id . '.json'; // 缓存存在且未过期(示例过期时间1小时) if (file_exists($cachePath) && (time() - filemtime($cachePath)) < 3600) { $content = file_get_contents($cachePath); } else { $content = file_get_contents("website.com/info/" . $id . ".json"); // 写入缓存,提前创建cache目录并给写入权限 file_put_contents($cachePath, $content); } return json_decode($content, true); }
3. 优化file_get_contents请求参数
如果不想改用cURL,也可以通过复用HTTP上下文减少file_get_contents的连接开销:
<?php // 提前创建上下文,复用连接 $context = stream_context_create([ 'http' => [ 'timeout' => 3, // 设置超时时间,避免请求卡死 'header' => 'Connection: keep-alive' ] ]); $site = file_get_contents('website.com/content.json', false, $context); $obj = json_decode($site, true); for ($i = 0; $i <= 9; $i++) { echo '<div class="result-' . $obj[$i]['id'] . '">'; // 复用同一个上下文发起请求 $info = json_decode(file_get_contents("website.com/info/" . $obj[$i]['id'] . ".json", false, $context), true); echo $info['content']; echo '</div>'; } ?>
4. 前端异步渲染兜底
如果以上优化还是不能满足加载速度要求,可以调整渲染逻辑:
- 后端先输出页面框架和所有的
result-*空div,不发起info请求 - 前端用JS并行发起所有info请求,拿到结果后填充到对应div中
这样后端页面首屏加载速度完全不受请求影响,用户感知的加载速度会明显提升。
内容的提问来源于stack exchange,提问作者Peter Brightt
相关产品推荐
相关产品推荐

