PHP脚本调用CoinMarketCap API响应迟缓,请求排查原因
解决CoinMarketCap API在PHP脚本中响应缓慢的问题
嘿,我看了你的问题和代码,发现问题大概率出在串行API请求上——如果你的$config里配置了多种加密货币,每次调用convertData都会单独发起一次curl请求,这些请求是一个接一个等待完成的,总耗时就是所有请求时间的累加,这正好匹配你说的页面加载11-13秒的情况(毕竟单独请求快,但多个串行就慢了)。
下面给你几个针对性的优化方案,按实现难度和效果排序:
1. 先加本地缓存(最快见效)
CoinMarketCap的行情数据不会每秒都更新,完全可以把请求到的数据缓存起来,比如缓存5分钟,这样大部分页面请求都不用真的去调用API,直接读本地缓存就行,速度会飞起来。
修改你的fetchData函数,加上缓存逻辑:
function fetchData($currency) { // 定义缓存文件路径和过期时间(这里设为5分钟=300秒) $cacheDir = __DIR__ . '/api_cache'; $cacheFile = $cacheDir . '/' . $currency . '.json'; $cacheExpire = 300; // 检查缓存是否有效 if (file_exists($cacheFile) && (time() - filemtime($cacheFile)) < $cacheExpire) { $response = file_get_contents($cacheFile); return json_decode($response, true); } // 缓存失效,发起API请求 $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_RETURNTRANSFER => 1, CURLOPT_URL => 'https://api.coinmarketcap.com/v1/ticker/'.$currency.'/?convert=EUR', CURLOPT_TIMEOUT => 10, // 设置超时,避免请求卡住 CURLOPT_FOLLOWLOCATION => true, CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' // 加个UA,避免被限流 )); $response = curl_exec($curl); // 处理请求失败的情况:如果有旧缓存就用旧的,否则返回空数组 if (curl_errno($curl)) { if (file_exists($cacheFile)) { $response = file_get_contents($cacheFile); } else { $response = json_encode([]); } } curl_close($curl); // 创建缓存目录(如果不存在)并写入缓存 if (!is_dir($cacheDir)) { mkdir($cacheDir, 0755, true); } file_put_contents($cacheFile, $response); return json_decode($response, true); }
2. 改用并行请求(适合需要准实时数据的场景)
如果你的业务需要相对新的数据,不想依赖缓存,那可以用curl_multi批量发起所有API请求,让这些请求同时进行,总耗时会接近单个请求的时间,而不是累加。
先写一个批量请求的函数:
function fetchMultipleCurrencies($currencies) { $multiHandle = curl_multi_init(); $curlHandles = []; $results = []; // 初始化所有curl请求 foreach ($currencies as $currency) { $url = 'https://api.coinmarketcap.com/v1/ticker/'.$currency.'/?convert=EUR'; $curlHandles[$currency] = curl_init(); curl_setopt_array($curlHandles[$currency], array( CURLOPT_RETURNTRANSFER => 1, CURLOPT_URL => $url, CURLOPT_TIMEOUT => 10, CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' )); curl_multi_add_handle($multiHandle, $curlHandles[$currency]); } // 执行并行请求 $running = null; do { curl_multi_exec($multiHandle, $running); curl_multi_select($multiHandle); } while ($running > 0); // 收集结果并清理资源 foreach ($curlHandles as $currency => $handle) { $results[$currency] = json_decode(curl_multi_getcontent($handle), true); curl_multi_remove_handle($multiHandle, $handle); curl_close($handle); } curl_multi_close($multiHandle); return $results; }
然后修改你的业务逻辑,先一次性拉取所有需要的货币数据,再处理:
// 先获取所有配置的货币列表 $targetCurrencies = array_keys($config); // 批量拉取数据 $allMarketData = fetchMultipleCurrencies($targetCurrencies); // 修改convertData函数,直接用批量获取的数据 function convertData($currency) { global $config, $allMarketData; $response = $allMarketData[$currency]; // 下面的逻辑和你原来的一样,不用再调用fetchData了 $id = $response[0]['id']; $name = $response[0]['name']; $value = $response[0]['price_eur']; $perc_change_h = $response[0]['percent_change_1h']; $perc_change_d = $response[0]['percent_change_24h']; $perc_change_w = $response[0]['percent_change_7d']; $amount = $config[$currency]['amount']; $starting_price = $config[$currency]['starting_price']; $spend = $amount * $starting_price; $total = $amount * $value; $profit = $total - $spend; return array( 'id' => $id, 'name' => $name, 'value' => round($value, 4), 'change_hour' => $perc_change_h, 'change_day' => $perc_change_d, 'change_week' => $perc_change_w, 'amount' => $amount, 'starting' => number_format($starting_price, 4), 'spend' => number_format($spend, 2), 'total' => number_format($total, 2), 'profit' => number_format($profit, 2) ); }
3. 其他小优化
- 给curl设置合理的超时时间(比如10秒),避免某个请求卡住拖慢整个页面
- 给请求加一个User-Agent,有些API会限制无UA的请求
- 检查你的服务器是否开启了curl的keep-alive(默认应该开启),减少TCP握手的时间
这两个方案结合起来用效果最好:平时读缓存,缓存过期时用并行请求更新缓存,既保证速度又能拿到较新的数据。
内容的提问来源于stack exchange,提问作者Kazuto
相关产品推荐
相关产品推荐

