Laravel 6中如何隐藏URL内的ID参数 无slug字段能否用title生成访问路径
核心疑问解答
不建议直接使用title实时生成slug实现隐藏ID的需求,现有逻辑无法直接适配,原因如下:
- 你当前的路由和查询逻辑完全依赖ID定位图片资源,去掉ID后没有字段可以唯一匹配到对应图片记录
- 如果每次请求都实时遍历所有图片记录,将title转为slug后和URL中的slug匹配,会带来极高的数据库查询开销,访问量稍大就会导致接口卡顿甚至服务不可用
- 存在重复风险:如果两张图片的title完全一致,生成的slug也会相同,会出现无法匹配到正确资源、甚至部分图片无法访问的问题
推荐实现方案
1. 数据库新增slug字段
给images表新增slug字段,类型设为字符串,加唯一索引:
ALTER TABLE images ADD COLUMN slug VARCHAR(255) UNIQUE NOT NULL;
批量生成已有数据的slug并入库,如果遇到重复可以在后面加数字后缀区分。后续新增/修改图片时,直接将生成的slug存入该字段。
2. 修改路由配置
将原有的带ID的路由调整为仅匹配slug:
// Photo Details Route::get('photo/{slug}','ImagesController@show');
3. 调整控制器逻辑
重写show方法的查询逻辑和URL校验逻辑:
public function show($slug) { // 直接用slug查询对应图片资源 $response = Images::where('slug', $slug)->firstOrFail(); $uri = $this->request->path(); // 生成规范的slug做校验,实现错误路径跳转 $canonicalSlug = str_slug($response->title); $uriCanonical = 'photo/'.$canonicalSlug; if( $uri != $uriCanonical ) { return redirect($uriCanonical); } // 后续原有业务逻辑保留 }
不新增字段的临时方案(极不推荐)
如果你暂时不想加字段,可以用以下方式实现,但性能和稳定性都很差,仅做参考:
// 控制器show方法 public function show($slug) { // 全表遍历匹配,性能极低 $response = Images::get()->filter(function($item) use ($slug) { return str_slug($item->title) == $slug; })->firstOrFail(); // 后续校验逻辑同上 }
这种方案在数据量超过1000条后就会出现明显的性能问题,且重复slug的问题无法解决,仅适合测试环境临时验证使用。
内容的提问来源于stack exchange,提问作者Gaurav Kumeriya
相关产品推荐
相关产品推荐

