You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel无法识别第二个传入参数,路由参数缺失报错排查

问题解决:Laravel路由参数缺失报错处理

问题背景

我需要向ShopController传递两个参数:路由组前缀的lang,以及链接传入的slug。控制器代码如下:

function show($lang, $slug)
{
    $product = Product::where('slug', $slug)->first();

    return view('shop_show')->with(['product' => $product]);
}

仅传一个参数时,该参数会被识别为路由组前缀的{lang},返回错误:Attempt to read property "name" on null,因此必须传递两个参数。

我已通过dump确认$lang和$slug值正确(比如$lang为"en",$slug为"laptop-1"),但执行后仍报错:

Missing required parameter for [Route: shopShow] [URI: {lang}/shop/{product}] [Missing parameter: product].

路由配置:

Route::group(['prefix' => '{lang}'], function () {
    Route::get('/shop/{product}', [ShopController::class, 'show'])->name('shopShow');
});

访问URL:http://127.0.0.1:8000/en/shop/laptop-9

更新:视图文件代码

以下是shop_show.blade.php的内容:

<x-layout :title="$product->name">
<section class="navbar py-2 border-bottom border-2" style="background-color: #eee; font-weight: 500">
    <div class="container w-75">
        <ul class="breadcrumb">
            <li class="breadcrumb-item">
                <a class="text-decoration-none" href="{{ route('landingPage', App::getLocale()) }}">Home</a>
            </li>

            <li class="breadcrumb-item">
                <a class="text-decoration-none" href="{{ route('shopIndex', App::getLocale()) }}">Shop</a>
            </li>

            <li class="breadcrumb-item">
                <a class="text-muted text-decoration-none" href="{{ route('shopShow', ['product' => $product->slug, 'lang' => App::getLocale()]) }}">{{$product->name}}</a>
            </li>
        </ul>
    </div>
</section>

<section class="my-5">
    <div class="container w-75 d-flex justify-content-between align-items-start">
        <div class="w-50">
            <div>
                <div>
                   <img id="currentImage" class="active border border-2 rounded-0 p-5 w-75" src='{{ $product->image && file_exists('storage/' . $product->image) ? asset('storage/' . $product->image) : asset('images/not-found.jpg') }}' alt="">
                </div>

                <div class="product-images">
                    <div class="product-thumbnails selected">
                        <img class="w-75" src='{{ $product->image && file_exists('storage/' . $product->image) ? asset('storage/' . $product->image) : asset('images/not-found.jpg') }}' alt="">
                    </div>
                    
                    @if ($product->images)
                        @foreach (json_decode($product->images, true) as $image)
                            <div class="d-flex align-items-center product-thumbnails">
                                <img class="w-75" src="{{ file_exists('storage/' . $image) ? asset('storage/' . $image) : asset('images/not-found.jpg') }}" alt="">
                            </div>
                        @endforeach
                    @endif
                </div>
            </div>
        </div>

        <div class="card border-0 w-50">
            <div>
                <h3 class="mb-5">
                    {{$product->name}}
                </h3>

                <span class="text-muted" style="font-weight: 500">
                    {{ $product->details }}
                </span>

                <div class="h3" style="font-weight: 700">
                    ${{$product->price / 100}}
                </div>

                <p class="my-3">
                    {!! $product->description !!}
                </p>

                <form action="{{ route('cartStore', App::getLocale()) }}" method="POST">
                    @csrf
                    <input type="hidden" name="name" value="{{$product->name}}">
                    <input type="hidden" name="price" value="{{$product->price}}">
                    <input type="hidden" name="id" value="{{$product->id}}">
                    <button class="btn py-2 px-3 border border-2 rounded-0 border-secondary" type="submit">Add to Cart</button>
                </form>
            </div>
        </div>
    </div>
</section>

@include('partials/might_also_like')

<script>
    const currentImage = document.querySelector('#currentImage');
    const images = document.querySelectorAll('.product-thumbnails');

    images.forEach((element) => element.addEventListener('click', thumbnailClick));

    function thumbnailClick(e) {
        currentImage.classList.remove('active');

        currentImage.addEventListener('transitionend', () => {
            currentImage.src = this.querySelector('img').src;
            currentImage.classList.add('active');
        })

        thumbnails.forEach((element) => element.classList.remove('selected'));
        this.classList.add('selected');
    }
</script>
</x-layout>

解决方案

1. 对齐路由与控制器的参数名

路由中定义的参数是{product},但控制器方法接收的是$slug,Laravel无法自动映射这两个参数,这是报错的核心原因。有两种修改方式:

  • 修改路由参数名:将路由中的{product}改为{slug},与控制器参数一致
Route::group(['prefix' => '{lang}'], function () {
    Route::get('/shop/{slug}', [ShopController::class, 'show'])->name('shopShow');
});
  • 修改控制器参数名:保持路由参数为{product},控制器接收$product并用于查询
function show($lang, $product)
{
    $product = Product::where('slug', $product)->first();

    return view('shop_show')->with(['product' => $product]);
}

2. 修正视图中路由生成的参数名

如果路由参数改为{slug},视图中的链接要同步修改参数名:

<a class="text-muted text-decoration-none" href="{{ route('shopShow', ['slug' => $product->slug, 'lang' => App::getLocale()]) }}">{{$product->name}}</a>

3. 处理商品不存在的情况

控制器中使用first()可能返回null,导致视图调用$product->name报错,改用firstOrFail()可以直接返回404页面,避免后续报错:

function show($lang, $slug)
{
    $product = Product::where('slug', $slug)->firstOrFail();

    return view('shop_show')->with(['product' => $product]);
}

4. 修复脚本中的变量错误

视图JS部分中thumbnails变量未定义,应改为已声明的images:

// 原代码
thumbnails.forEach((element) => element.classList.remove('selected'));
// 修改后
images.forEach((element) => element.classList.remove('selected'));

内容的提问来源于stack exchange,提问作者Eric SsSnake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 20:25:16