You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel分类页面加载缓慢:Helper类curl请求优化求助

解决Laravel分类页加载缓慢的问题

你的问题核心很明确:每个商品渲染时都调用Helper::getPRBcurr(),导致最多890次重复的缓存检查甚至外部API请求,哪怕有500ms超时,叠加起来的延迟也足以让页面卡顿。下面是几个逐步优化的解决方案,从最易实施到彻底根治:


1. 最直接的修复:提前获取一次汇率,复用给所有商品

现在的模板里,每个商品都会触发一次Helper::getPRBcurr()调用——哪怕缓存命中,890次缓存查询也是没必要的开销;如果缓存过期,890个并发的curl请求直接会把页面拖垮。

解决方法是在控制器里提前获取一次汇率,然后传递给视图,所有商品共用这个值:

控制器代码修改:

public function showCategory($categoryId)
{
    // 先获取分类下的商品
    $products = Product::where('category_id', $categoryId)->get();
    // 只调用一次汇率方法,把结果存到变量里
    $prbCurrency = Helper::getPRBcurr();
    // 把商品和汇率一起传给视图
    return view('category', compact('products', 'prbCurrency'));
}

商品模板(product.blade.php)修改:

把原来的Helper::getPRBcurr()调用换成传入的变量:

<div class="price-prb"> 
    <span itemprop="price"> 
        @php $prb = intval($product->price * $prbCurrency); @endphp 
        {{ $prb }} 
        <span itemprop="priceCurrency" content="PRB"> 
            {!! trans_choice('messages.currency.RUB', $prb) !!}
        </span> 
    </span> 
</div>

这样不管有多少个商品,只会发起一次汇率查询(缓存命中则直接取缓存,否则一次curl请求),瞬间消除重复调用的开销。


2. 优化Helper类:防止缓存击穿(并发请求问题)

即使做了上面的优化,还是要考虑缓存过期时的并发请求问题:如果缓存刚好失效,此时有多个用户访问分类页,还是会触发多次curl请求。我们可以给Helper类加锁,保证同一时间只有一个请求去拉取汇率,其他请求等待或者使用旧值。

修改Helper::getPRBcurr()方法:

static public function getPRBcurr()
{
    // 先尝试从缓存获取
    $currency = Cache::get('currency_prb_ee_agroTimeout');
    if ($currency) {
        return $currency;
    }

    // 使用缓存锁,10秒内只允许一个请求去拉取汇率
    $lock = Cache::lock('currency_prb_fetch_lock', 10);

    try {
        // 再次检查缓存,防止等待锁的过程中已经被其他请求更新了
        $currency = Cache::get('currency_prb_ee_agroTimeout');
        if ($currency) {
            return $currency;
        }

        // 发起curl请求获取汇率
        $contentCurrency = self::file_get_contents_curl('https://www.agroprombank.com/xmlinformer.php');
        if (!$contentCurrency) {
            // 拉取失败时用存储的旧值,临时缓存60秒
            $_currency = Storage::get('currency_prb_agro');
            Cache::put('currency_prb_ee_agroTimeout', $_currency, 60);
            return $_currency;
        }

        // 解析XML并处理汇率值
        $xmls = simplexml_load_string($contentCurrency);
        $currency = (string)$xmls->course[1]->currency[5]->currencySell;
        $currency = ($currency > 0) ? $currency : null;
        $currency = (strpos($currency, '1.0') !== false) ? '0.99' : $currency;

        // 更新缓存和存储
        Cache::put('currency_prb_ee_agroTimeout', $currency, 720);
        Storage::put('currency_prb_agro', $currency);

        return $currency;
    } finally {
        // 释放锁
        if ($lock->get()) {
            $lock->release();
        }
    }
}

这个修改确保了缓存过期时,只有一个请求会去调用外部API,其他请求要么等待锁释放后使用新缓存,要么在锁超时前返回旧值,避免了并发请求叠加的问题。


3. 终极方案:用任务调度预加载汇率

如果想彻底消除前端请求对外部API的依赖,可以用Laravel的任务调度,定期自动拉取汇率并更新缓存。这样用户的请求永远只会读取缓存,不会触发任何curl请求。

步骤1:创建Artisan命令

运行以下命令生成命令文件:

php artisan make:command UpdatePRBCurrency

步骤2:编写命令逻辑

打开app/Console/Commands/UpdatePRBCurrency.php,修改handle()方法:

public function handle()
{
    $contentCurrency = Helper::file_get_contents_curl('https://www.agroprombank.com/xmlinformer.php');
    
    if (!$contentCurrency) {
        $this->error('Failed to fetch PRB currency from API');
        return 1; // 标记命令执行失败
    }

    $xmls = simplexml_load_string($contentCurrency);
    $currency = (string)$xmls->course[1]->currency[5]->currencySell;
    $currency = ($currency > 0) ? $currency : null;
    $currency = (strpos($currency, '1.0') !== false) ? '0.99' : $currency;

    Cache::put('currency_prb_ee_agroTimeout', $currency, 720);
    Storage::put('currency_prb_agro', $currency);

    $this->info('PRB currency updated successfully!');
    return 0;
}

步骤3:配置任务调度

打开app/Console/Kernel.php,在schedule()方法里添加调度规则:

protected function schedule(Schedule $schedule)
{
    // 每小时自动更新一次汇率
    $schedule->command('update:prb-currency')->hourly();
}

最后,确保你的服务器配置了Laravel调度器的 cron 任务(可以参考Laravel官方文档的调度器配置)。这样缓存会被定期更新,用户访问页面时永远读取的是缓存值,彻底解决外部API调用带来的延迟问题。


内容的提问来源于stack exchange,提问作者Jadasdas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:49:34