如何重构点赞方法以实现两种点赞类型的24小时独立限制(基于Cookie存储)
解决方案:实现单用户24小时单类型点赞限制
针对你的需求,我们需要调整现有代码,确保用户每24小时对同一文章的指定点赞类型只能操作一次,同时保证Cookie存储格式符合要求,正确更新数据库的like_heart和like_finger字段。以下是分步实现方案:
1. 修正User模型的核心方法
我们需要完善点赞校验、Cookie更新和数据库计数递增的逻辑,同时加入类型合法性校验:
class User extends Authenticatable { const LIKE_HEART = 'like_heart'; const LIKE_FINGER = 'like_finger'; public static $validTypes = [self::LIKE_HEART, self::LIKE_FINGER]; // 检查用户是否已在24小时内给该文章的指定类型点过赞 public static function hasLikedToday($articleId, string $type) { // 非法类型直接拦截 if (!in_array($type, self::$validTypes)) { return true; } $articleLikesJson = \Cookie::get('article_likes', '{}'); $articleLikes = json_decode($articleLikesJson, true); // 校验该文章的指定类型点赞是否在24小时冷却期内 if (isset($articleLikes[$articleId][$type])) { $likeDatetime = Carbon::parse($articleLikes[$articleId][$type]); return $likeDatetime->addHours(24)->gt(now()); } return false; } // 更新Cookie中的点赞记录 public static function setLikeCookie($articleId, string $type) { if (!in_array($type, self::$validTypes)) { throw new \InvalidArgumentException('Invalid like type'); } $articleLikesJson = \Cookie::get('article_likes', '{}'); $articleLikes = json_decode($articleLikesJson, true); // 更新对应文章的指定类型点赞时间为当前时间 $articleLikes[$articleId][$type] = now()->format('Y-m-d H:i:s'); $articleLikesJson = json_encode($articleLikes); // 设置永久Cookie(可根据需求调整有效期) return cookie()->forever('article_likes', $articleLikesJson); } // 递增数据库中的对应点赞字段 public static function incrementLikeCount($articleId, string $type) { if (!in_array($type, self::$validTypes)) { return false; } return \App\Models\Article::where('id', $articleId)->increment($type); } }
2. 优化控制器的点赞处理逻辑
完善参数验证、校验逻辑、数据库更新和响应处理:
public function postLike(Request $request) { // 验证请求参数合法性 $request->validate([ 'id' => 'required|integer|exists:articles,id', 'type' => 'required|string|in:like_heart,like_finger' ]); $articleId = $request->input('id'); $type = $request->input('type'); // 检查是否在冷却期内 if (User::hasLikedToday($articleId, $type)) { return response()->json([ 'message' => "You've already liked article #{$articleId} with {$type} in the last 24 hours.", 'success' => false ], 403); } // 更新数据库点赞数 $incremented = User::incrementLikeCount($articleId, $type); if (!$incremented) { return response()->json([ 'message' => 'Failed to update like count.', 'success' => false ], 500); } // 设置点赞记录Cookie $cookie = User::setLikeCookie($articleId, $type); return response()->json([ 'message' => "Successfully liked article #{$articleId} with {$type}.", 'success' => true ])->withCookie($cookie); }
3. 修正路由配置
调整路由参数和请求方式(推荐用POST更符合REST规范):
// 文章详情页路由(保留原有逻辑) Route::get('/article/{slug}', 'App\Http\Controllers\ArticleController@index'); // 点赞路由(优先POST,兼容GET可选) Route::post('/article/{id}/like', 'App\Http\Controllers\ArticleController@postLike'); Route::get('/article/{id}/like', 'App\Http\Controllers\ArticleController@postLike');
4. 调整视图的点赞交互
将原GET链接改为AJAX提交的按钮,提升用户体验并避免缓存问题:
<!-- 替换原点赞链接为按钮 --> <button class="btn btn-primary like-btn" data-id="{{ $article->id }}" data-type="like_heart">Like Heart</button> <button class="btn btn-primary like-btn" data-id="{{ $article->id }}" data-type="like_finger">Like Finger</button> <!-- 确保页面包含CSRF令牌 --> <meta name="csrf-token" content="{{ csrf_token() }}"> <!-- 添加AJAX交互脚本 --> <script> document.querySelectorAll('.like-btn').forEach(btn => { btn.addEventListener('click', async function() { const articleId = this.dataset.id; const type = this.dataset.type; // 禁用按钮防止重复提交 this.disabled = true; try { const response = await fetch(`/article/${articleId}/like`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify({ id: articleId, type: type }) }); const data = await response.json(); alert(data.message); // 可在这里添加更新页面点赞数的逻辑 } catch (error) { alert('Failed to process your like request.'); } finally { // 恢复按钮可用状态 this.disabled = false; } }); }); </script>
5. Cookie格式验证
最终Cookie存储的JSON结构与你要求的PHP数组完全对应,示例如下:
{ "1": { "like_heart": "2024-05-20 14:30:00", "like_finger": "2024-05-20 15:45:00" }, "2": { "like_finger": "2024-05-19 10:12:34" } }
关键逻辑说明
- 类型校验:通过
$validTypes确保只有合法的点赞类型能被处理,避免非法请求 - 冷却期判断:使用Carbon工具类准确计算24小时时间窗口,防止重复点赞
- 原子操作:仅当校验通过后才执行数据库递增操作,保证数据一致性
- 持久化记录:通过永久Cookie存储用户点赞记录,跨会话生效
内容的提问来源于stack exchange,提问作者chu
相关产品推荐
相关产品推荐

