Laravel 8实现商品最近浏览cookie存储:如何追加ID并去重
核心问题根源
- 此前逻辑要么直接覆盖旧Cookie值,要么通过字符串拼接构造数据后多层JSON编码,导致转义混乱
- 未全程使用PHP数组操作,最终存储的Cookie结构不符合预期的一维ID数组
- 未做去重、条数限制处理
正确实现代码
1. 控制器(ProductController@show)逻辑
// 读取已存在的Cookie并解码为一维数组,不存在则初始化为空数组 $recentlyViewed = json_decode(request()->cookie('recently_viewed'), true) ?? []; // 移除当前商品ID的旧记录(去重核心逻辑) $recentlyViewed = array_diff($recentlyViewed, [$product->id]); // 将当前商品ID加入数组(若需最新浏览排最前用array_unshift,排最后用array_push) array_unshift($recentlyViewed, $product->id); // 限制最多保存10条记录(避免Cookie超过4KB的浏览器限制) $recentlyViewed = array_slice($recentlyViewed, 0, 10); // 将一维数组编码为JSON字符串存入Cookie,过期时间单位为*分钟* Cookie::queue( 'recently_viewed', json_encode($recentlyViewed), 1440 // 示例:1天(1440分钟),可按需调整 );
注意:Laravel默认加密所有Cookie,必须使用request()->cookie()或Cookie::get()读取,不能用原生$_COOKIE超全局变量。
测试提示:Laravel的Cookie::queue()会在当前响应完成时才将Cookie写入客户端,需刷新页面后才能看到Cookie值的更新,属于正常现象。
2. Blade模板渲染逻辑
@php // 读取Cookie并解码为一维数组,处理空值 $recentlyViews = json_decode(Cookie::get('recently_viewed'), true) ?? []; @endphp {{-- 仅当存在浏览记录时渲染 --}} @if (count($recentlyViews)) <div class="recently-viewed-products"> <h4>最近浏览的商品</h4> <ul> @foreach ($recentlyViews as $productId) {{-- 推荐先在控制器中批量查询商品(避免N+1问题),此处示例为简化 --}} @php($recentProduct = \App\Models\Product::find($productId)) @if ($recentProduct) <li> <a href="{{ route('products.show', $recentProduct->id) }}"> {{ $recentProduct->name }} </a> </li> @endif @endforeach </ul> </div> @endif
此时Cookie存储的格式完全符合需求,解码后为标准一维索引数组:
[ 0 => 4, 1 => 1, 2 => 5, ]
优化建议
- 避免N+1查询:在控制器中批量查询ID对应的商品集合,而非Blade中循环单查:
// 控制器中,拿到$recentlyViewed数组后批量查询 $recentProducts = \App\Models\Product::whereIn('id', $recentlyViewed)->get(); // 将$recentProducts传递给Blade视图,直接循环该集合
- 后续数据库同步:因Cookie存储的是干净的ID数组,后续可直接读取该数组,同步写入用户浏览历史表,无需处理转义或格式问题
- 过期时间调整:若需长期保存,可将
Cookie::queue()第三个参数设为10080(1周)或更长
内容的提问来源于stack exchange,提问作者Yousef Altaf
相关产品推荐
相关产品推荐

