Laravel8实现旅游对象点赞评论提交后返回404错误排查
问题定位与修复方案
你看到的是Apache返回的原生404响应,不是Laravel框架抛出的异常,核心原因是请求根本没有进入Laravel的路由解析流程,直接被Web服务器判定为不存在的物理路径。
核心诱因
路由参数type传递的值为App\TouristObject,包含反斜杠\,该字符会被Apache识别为路径分隔符,最终实际请求路径被解析为/like/1/App/TouristObject这类多级路径,和你定义的路由规则完全不匹配,且服务器上不存在对应物理文件,直接返回404。
分步修复方案
1. 修复路由参数特殊字符问题
第一步:给路由添加参数正则约束
修改路由定义,允许type参数包含斜杠类特殊字符:
// routes/web.php Route::get('/like/{likeable_id}/{type}','FrontendController@like') ->name('like') ->where('type', '.*'); Route::get('/unlike/{likeable_id}/{type}','FrontendController@unlike') ->name('unlike') ->where('type', '.*'); Route::post('/addComment/{commentable_id}/{type}','FrontendController@addComment') ->name('addComment') ->where('type', '.*');
第二步:对类名参数做编码传递
不要直接把带反斜杠的类名拼在URL里,在视图层生成路由时对类名做base64编码,避免破坏URL结构:
- 点赞/取消点赞链接修改:
@auth @if( $touristObject->isLiked() ) <a href="{{ route('unlike', [ 'likeable_id' => $touristObject->id, 'type' => base64_encode('App\TouristObject') ]) }}" class="btn btn-primary btn-xs top-buffer">Odlub ten obiekt</a> @else <a href="{{ route('like', [ 'likeable_id' => $touristObject->id, 'type' => base64_encode('App\TouristObject') ]) }}" class="btn btn-primary btn-xs top-buffer">Polub ten obiekt</a> @endif @else <p><a href="{{ route('login') }}">Zaloguj się aby polubić obiekt</a></p> @endauth
- 评论表单action修改:
<form method="POST" action="{{ route('addComment', [ 'commentable_id' => $touristObject->id, 'type' => base64_encode('App\TouristObject') ]) }}" class="form-horizontal"> @csrf {{-- 必须加CSRF令牌,否则POST请求会报419错误 --}} <fieldset> <!-- 原有表单内容保持不变 -->
第三步:控制器层解码参数
在控制器中拿到type参数后先做base64解码,再传递给下层逻辑:
// FrontendController.php public function like($likeable_id, $type, Request $request) { $type = base64_decode($type); $this->fR->like($likeable_id, $type, $request); return redirect()->back(); } public function unlike($likeable_id, $type, Request $request) { $type = base64_decode($type); $this->fR->unlike($likeable_id, $type, $request); return redirect()->back(); } public function addComment($commentable_id, $type, Request $request) { $type = base64_decode($type); $this->fG->addComment($commentable_id, $type, $request); // 原有逻辑漏了调用网关层,直接调仓库会跳过参数校验 return redirect()->back(); }
2. 确认Apache重写规则生效
如果改完上述内容还是返回Apache原生404,检查两点配置:
- 站点根目录必须指向Laravel项目的
public文件夹,不能指向项目根目录 - Apache已经开启
mod_rewrite模块,且public目录下默认的.htaccess文件没有被删除,允许URL重写生效。
验证方式:访问Laravel自带的/login路由,如果能正常打开登录页,说明重写规则正常。
现有代码其他隐患修复
- 修复
isLiked方法的游客访问报错问题:游客访问时Auth::user()为null,直接调用会抛出空指针错误,修改模型方法:
// TouristObject.php public function isLiked() { if (!auth()->check()) { return false; } return $this->users()->where('user_id', auth()->id())->exists(); }
- 修复评论功能rating字段赋值错误:原有代码把评论内容赋值给了数字类型的rating字段,修改仓库层逻辑:
// FrontendRepository.php public function addComment($commentable_id, $type, $request) { $commentable = $type::find($commentable_id); $comment = new Comment; $comment->content = $request->input('content'); // 原错误写法是把content赋值给rating,这里改为取请求中的rating值,默认0 $comment->rating = $type == 'App\TouristObject' ? (int)$request->input('rating', 0) : 0; $comment->user_id = $request->user()->id; return $commentable->comments()->save($comment); }
优化建议:不要在URL中直接传递完整类名,既存在特殊字符问题,也有安全风险(攻击者可构造参数实例化其他类)。可以在控制器中维护类型映射表,例如
$typeMap = ['object' => \App\TouristObject::class],前端只需要传递短标识object,后端从映射表取对应类名,从根源规避特殊字符问题。
内容的提问来源于stack exchange,提问作者Weronika Piotrowicz
相关产品推荐
相关产品推荐

