
本文介绍如何将依赖 `` 标签的点赞逻辑重构为纯 ajax 驱动的交互方式,避免 get 请求被误判为页面导航、消除 405 method not allowed 报错,并保持前端响应与状态同步。
在当前实现中,点赞按钮使用 php.cn/link/5c1697b2090acdf06d589303b060b78a"> 这类超链接,虽配合 event.preventDefault() 阻止了默认跳转,但搜索引擎爬虫或浏览器预加载机制仍可能尝试以 GET 方式访问该 URL,而你的后端路由仅接受 POST /article/{id}(由 postLike 控制器处理),导致返回 405 错误——这是典型的「语义误用」问题:超链接()天然代表导航,不应承载写操作(如点赞)。
✅ 正确做法:语义化 + 解耦 + 安全交互
1. 替换 为语义中立的 或
移除 href 属性带来的副作用,改用 data-* 属性携带业务参数:
✅ 优势: 消除 href 引发的预加载/爬虫请求; button[type="button"] 明确表示非提交、非导航行为; 保留 data-id 和 data-type 供 JS 安全读取。
2. 前端 AJAX 改为显式 POST 请求(推荐)
虽然答案中建议改用 GET,但点赞是修改服务端状态的操作,必须使用 POST(或 PATCH/PUT),符合 REST 语义与 CSRF 防护要求:
$('.like-button').on('click', function (e) {
e.preventDefault();
const $btn = $(this);
const articleId = $btn.data('id');
const type = $btn.data('type');
// 禁用按钮防重复点击(可选但强烈推荐)
$btn.prop('disabled', true);
$.ajax({
url: `/article/${articleId}/like`, // 统一路由,更清晰
type: 'POST',
data: { type: type },
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
success: function (res) {
if ($btn.hasClass('active')) return;
const $counter = $btn.find('.comments-sub-header__item-icon-count');
const current = parseInt($counter.text()) || 0;
$counter.text(current + 1);
$btn.addClass('active');
},
error: function (xhr) {
if (xhr.responseJSON?.message) {
alert(xhr.responseJSON.message); // 或使用 Toast 提示
}
},
complete: function () {
$btn.prop('disabled', false);
}
});
});3. 后端路由与控制器适配(关键!)
更新 routes/web.php,注册显式 POST 路由(避免与文章展示页 /article/{id} 冲突):
立即学习“前端免费学习笔记(深入)”;
// routes/web.php
Route::post('/article/{id}/like', [ArticleController::class, 'postLike'])->name('article.like');控制器保持不变(已支持 POST),但建议增强健壮性:
public function postLike($id, Request $request)
{
$article = Article::findOrFail($id); // 使用 findOrFail 替代手动 abort
$type = $request->input('type');
if (!in_array($type, ['heart', 'finger'])) {
return response()->json(['message' => 'Invalid like type'], 400);
}
if ($article->hasLikedToday($type)) {
return response()->json([
'message' => "You've already liked article {$id} with {$type} today."
], 403);
}
$cookie = $article->setLikeCookie($type);
$article->increment("like_{$type}");
return response()->json([
'message' => "Liked article {$id} with {$type}.",
'count' => $article->{"getLike{$type->ucfirst()}Total"}() // 动态获取最新计数(可选)
])->withCookie($cookie);
}⚠️ 注意事项
- 永远不要用 GET 请求执行写操作:违反 HTTP 规范,易被缓存、书签、日志记录,且无法携带 CSRF Token。
- Cookie 安全性:当前基于 Cookie 的本地去重仅作体验优化,不可替代服务端幂等校验(你已在 hasLikedToday() 中做了,很好)。
- SEO 友好提示:若需搜索引擎理解点赞行为,可在 中添加 rel="nofollow"(对按钮无效,故无需);真正重要的是确保文章页本身结构清晰、内容优质。
- 无障碍支持:
✅ 总结
通过三步重构——替换标签语义、统一 POST 接口、强化前后端协同校验——即可彻底解决 405 报错,同时提升代码可维护性、安全性与用户体验。点赞本质是“用户意图 + 状态变更”,应由明确的交互控件(button)发起,经受控的 API(POST)执行,而非伪装成导航链接。











