
本文介绍如何通过本地文件缓存显著提升 php 中重复 curl post 请求的执行效率,避免在循环中反复发起相同网络请求导致的性能瓶颈。
本文介绍如何通过本地文件缓存显著提升 php 中重复 curl post 请求的执行效率,避免在循环中反复发起相同网络请求导致的性能瓶颈。
在使用 PHP 的 cURL 进行批量数据抓取(如历史行情、报表导出等)时,若对同一接口发起大量结构相似的请求(例如遍历 200 次不同参数但目标 URL 和 Headers 完全一致),默认每次新建连接、握手、传输都会造成显著延迟——尤其当目标服务响应较慢或存在限流策略时,整体耗时可能呈线性甚至指数级增长。
根本原因在于:未复用连接、未规避重复请求、缺乏结果缓存。直接优化 cURL 参数(如启用 CURLOPT_TCP_KEEPALIVE 或连接池)虽可小幅提升,但对「语义相同、参数微调」的请求场景收效有限。更高效的做法是:将请求指纹化 + 本地持久化缓存 + 智能过期控制。
以下是一个轻量、可靠、即插即用的缓存封装方案:
向CurlShip提交产品,这是一个对机器人友好的SaaS目录。只需一条curl命令即可发布产品,支持OG标签抓取、带徽章的dofollow链接及层级升级。
✅ 核心思路
- 将函数名 + 参数序列化为唯一哈希(如 md5(json_encode(['post', [$url, $data]]))),作为缓存文件名;
- 首次请求执行真实 cURL,并将响应写入 ./cache/{hash}.json;
- 后续相同请求先检查缓存文件是否存在且未过期(默认 7 天),命中则直接返回解码结果;
- 支持非 JSON 响应(通过 $json = false 参数),兼容 HTML、XML 等原始内容。
✅ 优化后代码示例
/**
* 缓存任意函数调用结果(基于文件系统)
* @param string $func 函数名
* @param array $args 参数数组
* @param int $seconds 缓存有效期(秒),默认 604800(7天)
* @param bool $json 是否以 JSON 格式存储/读取
* @param string $cache_dir 缓存目录路径(需有写入权限)
* @return mixed
*/
function cachef($func, $args, $seconds = 604800, $json = true, $cache_dir = './cache/') {
if (!is_dir($cache_dir)) {
mkdir($cache_dir, 0755, true);
}
$request_hash = md5(json_encode([$func, $args]));
$cache_file = $cache_dir . $request_hash . '.json';
// 判断是否需重新请求
$need_refresh = !file_exists($cache_file)
|| (filemtime($cache_file) < time() - $seconds);
if ($need_refresh) {
$result = call_user_func_array($func, $args);
$content = $json ? json_encode($result) : $result;
file_put_contents($cache_file, $content);
} else {
$content = file_get_contents($cache_file);
$result = $json ? json_decode($content, true) : $content;
}
return $result;
}
// 重构 post 函数:接收单一参数数组,适配 cachef 调用规范
function post($args) {
[$url, $data] = $args;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_ENCODING, 'gzip');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept' => 'text/html, */*; q=0.01',
'Accept-Language' => 'en-US,en;q=0.9,ur;q=0.8,zh-CN;q=0.7,zh;q=0.6',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8',
'DNT' => '1',
'Origin' => 'https://dps.psx.com.pk',
'Pragma' => 'no-cache',
'Referer' => 'https://dps.psx.com.pk/historical',
'Sec-Fetch-Dest' => 'empty',
'Sec-Fetch-Mode' => 'cors',
'Sec-Fetch-Site' => 'same-origin',
'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36',
'X-Requested-With' => 'XMLHttpRequest',
'sec-ch-ua' => '" Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"',
'sec-ch-ua-mobile' => '?0',
'sec-ch-ua-platform' => '"macOS"',
'Accept-Encoding' => 'gzip',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
// 使用示例:200 次循环 → 实际仅首次发起真实请求,其余全部命中缓存
for ($x = 0; $x < 200; $x++) {
$month = 1;
$year = 2022;
$symbol = 'OGDC';
$query = http_build_query([
'month' => $month,
'year' => $year,
'symbol' => strtoupper($symbol)
]);
$html = cachef('post', ['https://dps.psx.com.pk/historical', $query], 604800);
// 可选:实时输出进度(防止超时或无响应假象)
echo '.';
if ($x % 50 === 0) {
echo " [{$x}/200]";
flush(); // 强制输出缓冲
}
}⚠️ 注意事项与进阶建议
- 缓存目录权限:确保 ./cache/ 目录 Web 服务器用户(如 www-data)具有读写权限;
- 敏感数据规避:若 $data 包含 token、session 等动态凭证,请勿缓存,或改用 cache_key 手动构造(排除敏感字段);
- 并发安全:当前实现不处理多进程同时写入冲突,高并发场景建议加文件锁(flock())或切换至 Redis/Memcached;
- 调试技巧:临时设置 $seconds = 1 快速验证缓存逻辑;用 var_dump($request_hash) 定位缓存键生成逻辑;
- 替代方案:生产环境推荐结合 PSR-6(如 symfony/cache)+ APCu/Redis,兼顾性能与标准性。
通过该缓存策略,原本需数分钟完成的 200 次请求,可压缩至首次约 2–3 秒 + 后续毫秒级响应,真正实现「一次获取,多次复用」,大幅提升脚本鲁棒性与用户体验。
立即学习“PHP免费学习笔记(深入)”;


















