Laravel 8如何移除或替换URL中的ID参数实现友好链接
问题描述
当前URL为 localhost:8000/product/sofa/10,希望实现两种URL效果:
- 简化为
localhost:8000/product/sofa - 替换ID为语义化标识,变为
localhost:8000/product/sofa/long
现有路由、HTML及控制器代码如下,请教实现方法:
现有代码
路由代码
Route::get('/product/sofa/{id}',[ProductSofaController::class,'sofa']);
HTML代码
<a href="/product/sofa/{{ $id = 10 }}"> <img loading="auto" src="{{ asset('media/category/bg-sofa.jpg') }}" alt="Sofa and Daybed"> </a>
控制器代码
public function sofa(Request $request, $id){ $frame = frames::where('pf_product_category_id',[$id,16]) ->where('pf_status',true)->with('linkProducts') ->get(); return view('frontend/sofa',compact('frame')); }
解决方案
情况1:实现 localhost:8000/product/sofa 无参数URL
- 修改路由:新增无参数路由(优先匹配),保留原路由兼容旧链接(可选)
// 新增无参数路由,命名方便生成链接 Route::get('/product/sofa',[ProductSofaController::class,'sofa'])->name('product.sofa'); // 保留原带ID的路由,用于兼容历史链接或其他场景 Route::get('/product/sofa/{id}',[ProductSofaController::class,'sofa']);
- 修改控制器:给
$id参数设置默认值10,无参数请求时自动使用该值
public function sofa(Request $request, $id = 10){ $frame = frames::where('pf_product_category_id',[$id,16]) ->where('pf_status',true)->with('linkProducts') ->get(); return view('frontend/sofa',compact('frame')); }
- 修改HTML链接:通过路由名称生成无参数URL
<a href="{{ route('product.sofa') }}"> <img loading="auto" src="{{ asset('media/category/bg-sofa.jpg') }}" alt="Sofa and Daybed"> </a>
情况2:实现 localhost:8000/product/sofa/long 语义化URL
通过语义化标识与数据库ID的映射,避免直接暴露ID:
- 修改路由:将参数名改为
slug(语义化命名,也可保留id)
Route::get('/product/sofa/{slug}',[ProductSofaController::class,'sofa'])->name('product.sofa.slug');
- 修改控制器:添加标识到ID的映射逻辑,用映射后的ID查询数据
public function sofa(Request $request, $slug){ // 定义语义化标识与数据库ID的映射关系 $slugMap = [ 'long' => 10, // 可扩展更多映射,如 'small' => 11 等 ]; // 获取对应ID,无匹配则返回404 $id = $slugMap[$slug] ?? abort(404, '无效分类'); $frame = frames::where('pf_product_category_id',[$id,16]) ->where('pf_status',true)->with('linkProducts') ->get(); return view('frontend/sofa',compact('frame')); }
- 修改HTML链接:使用语义化标识生成URL
<a href="{{ route('product.sofa.slug', ['slug' => 'long']) }}"> <img loading="auto" src="{{ asset('media/category/bg-sofa.jpg') }}" alt="Sofa and Daybed"> </a>
兼容两种URL的方案
若需要同时支持无参数和语义化参数URL,可配置两条路由并调整控制器:
// 无参数路由 Route::get('/product/sofa',[ProductSofaController::class,'sofa'])->name('product.sofa'); // 语义化参数路由 Route::get('/product/sofa/{slug}',[ProductSofaController::class,'sofa'])->name('product.sofa.slug');
控制器兼容逻辑:
public function sofa(Request $request, $slug = null){ $defaultId = 10; $slugMap = [ 'long' => 10, // 其他映射 ]; // 无参数时用默认ID,有参数时匹配映射 $id = is_null($slug) ? $defaultId : ($slugMap[$slug] ?? abort(404)); $frame = frames::where('pf_product_category_id',[$id,16]) ->where('pf_status',true)->with('linkProducts') ->get(); return view('frontend/sofa',compact('frame')); }
内容的提问来源于stack exchange,提问作者rista
相关产品推荐
相关产品推荐

