在使用Laravel 8时出现“目标类控制器不存在”错误。

327

这是我的控制器:

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class RegisterController extends Controller
{
    public function register(Request $request)
    {
        dd('aa');
    }
}

正如屏幕截图所示,该类存在且位于正确的位置:

在此输入图片描述

我的api.php路由:

Route::get('register', 'Api\RegisterController@register');
当我在Postman中访问register路由时,出现了以下错误:

目标类[Api\RegisterController]不存在。

如何解决?


多亏了回答中的建议,我已经修复了它。我决定为此路由使用完全合格的类名,但还有其他选项,如答案中所述。

Route::get('register', 'App\Http\Controllers\Api\RegisterController@register');

1
欢迎来到 SO..你的控制器是否在 Api 文件夹内? - Kamlesh Paul
4
您需要重新生成类,可以通过执行 composer dump-autoload 命令来实现,或者在您的 RegisterController 中添加缺失的命名空间。 - STA
2
然后尝试运行 composer dump-autoload - Kamlesh Paul
5
找到了解决这个问题的正确方法:https://www.scratchcode.io/laravel-8-target-class-controller-does-not-exist/。 - Mayank Dudakiya
1
如果你想在 Laravel 8 中使用资源路由,则使用以下代码: Route::resource('xyz', App\Http\Controllers\XyzController::class); - Muhammad Shahzad
显示剩余5条评论
32个回答

596

您正在使用 Laravel 8。在 Laravel 8 的全新安装中,未对加载路由的路由组应用命名空间前缀。

"在先前的 Laravel 版本中,RouteServiceProvider 含有一个 $namespace 属性。该属性的值会自动作为控制器路由定义和调用 action 帮助程序/URL::action 方法的前缀。在 Laravel 8.x 中,该属性默认为 null。这意味着 Laravel 不会自动添加命名空间前缀。" Laravel 8.x 文档 - 发布说明

如果不使用命名空间前缀,则在路由中引用控制器时必须使用完全限定类名。

use App\Http\Controllers\UserController;

Route::get('/users', [UserController::class, 'index']);
// or
Route::get('/users', 'App\Http\Controllers\UserController@index');

如果您喜欢旧的方式:

App\Providers\RouteServiceProvider:

public function boot()
{
    ...

    Route::prefix('api')
        ->middleware('api')
        ->namespace('App\Http\Controllers') // <---------
        ->group(base_path('routes/api.php'));

    ...
}

对于您想要声明命名空间的任何路由组,请进行以下操作。

$namespace 属性:

尽管在发布说明中提到需要在 RouteServiceProvider 上设置一个 $namespace 属性,而且在您的 RouteServiceProvider 中也有注释,但它不会影响您的路由。目前它只用于为生成操作URL添加命名空间前缀。因此,您可以设置此变量,但它本身不会添加这些命名空间前缀,您仍然必须确保在将命名空间添加到路由组时使用该变量。

升级指南中包含了此信息

Laravel 8.x 文档 - 升级指南 - 路由

根据升级指南所示,重要的部分是您正在为路由组定义命名空间。仅设置 $namespace 变量本身仅有助于生成操作URL。

再次强调一下,重要的部分是设置路由组的命名空间,在示例中他们恰好通过直接引用成员变量 $namespace 来实现。

更新:

如果您自 Laravel 8.0.2 版本以来安装了新的 Laravel 8 副本,则可以取消注释 RouteServiceProvider 中的 protected $namespace 成员变量,以回到旧方式,因为路由组设置为使用此成员变量作为组的命名空间。

// protected $namespace = 'App\\Http\\Controllers';

只有一种情况会取消注释,那就是将此变量用作名称空间而设置的路由组才会将名称空间前缀添加到分配给路由的控制器中:

...
->namespace($this->namespace)
...

6
这真的让我很疯狂。在$namespace变量上面的注释说:“如果指定,这个命名空间会自动应用于你的控制器路由。”但是它并没有这样做。你必须像你指出的那样添加->namespace('App\Http\Controllers')。他们真的应该改变源代码中的注释... - shock_gone_wild
2
修改是为了什么?是为了提高性能吗? - CodeGuru
1
@WesleySmith,从 laravel/laravel 的 8.0.2 版本开始,现在您可以取消注释并使用该功能。 - lagbox
4
@lagbox:因为有像 Stack Overflow 和你这样的人,世界变得美妙无比... - DragonFire
2
您,先生/女士/朋友,是一个传奇。我想给您打赏10美元的IOTA。如果您不知道什么是IOTA(https://howtobuyiota.co.uk/what-is-iota/)。如果您知道,请告诉我您的接收地址。 - JamesG
显示剩余7条评论

83
  • Laravel 8 中确实会出现这个错误。
  • 尝试了许多解决方案后,我找到了这个完美的解决方案。
  • 只需按照以下步骤操作...

情况1

我们可以像下面这样更改api.phpweb.php文件中的语法。 我们目前编写syntax的方式是

Route::get('login', 'LoginController@login');

应该将其更改为:

Route::get('login', [LoginController::class, 'login']);

案例2

  1. 首先打开文件:app > Providers > RouteServiceProvider.php

  2. 在该文件中将protected $namespace = null;这行替换为protected $namespace = 'App\Http\Controllers';

    Enter image description here

  3. 然后像图中所示添加一行->namespace($this->namespace)

    Enter image description here


1
关于第一种情况,如果我们有一个资源控制器,那么该怎么办?也就是说,没有特定的函数要指定吗? - Berni
1
Route::resource("proxies", ProxyController::class) fails with class not found error. It use namespace twice \App\Http\Controllers\App\Http\Controllers\ProxyController - teran
1
谢谢,这就像魔法一样有效。 - Ademaintain
我现在得到 404 未找到 - ChrisDeDavidMindflowAU

26

在 Laravel 8 中定义你的路由方式有两种:

// Using PHP callable syntax...
use App\Http\Controllers\HomeController;
Route::get('/', [HomeController::class, 'index']);
或者
// Using string syntax...
Route::get('/', 'App\Http\Controllers\HomeController@index');

一个资源路由成为

// Using PHP callable syntax...
use App\Http\Controllers\HomeController;
Route::resource('/', HomeController::class);

这意味着在 Laravel 8 中,默认情况下没有自动控制器声明前缀。

如果您想坚持旧的方式,则需要在 app\Providers\RouteServiceProvider.php中添加命名空间属性,并在路由方法中激活它。


23
在Laravel 8中,您只需在routes\web.php中添加您的控制器命名空间。
use App\Http\Controllers\InvoiceController; // InvoiceController is controller name

Route::get('invoice',[InvoiceController::class, 'index']);

或者前往:app\Providers\RouteServiceProvider.php 路径并移除注释:

protected $namespace = 'App\\Http\\Controllers';

23
在Laravel 8中,默认情况下会删除命名空间前缀,所以您可以像在Laravel 7中一样设置旧方式:

RouteServiceProvider.php中,添加此变量:


protected $namespace = 'App\Http\Controllers';

并更新boot方法:

public function boot()
{
    $this->configureRateLimiting();

    $this->routes(function () {
        Route::middleware('web')
            ->namespace($this->namespace)
            ->group(base_path('routes/web.php'));

        Route::prefix('api')
            ->middleware('api')
            ->namespace($this->namespace)
            ->group(base_path('routes/api.php'));
    });
}

15
我在安装 Laravel 8.27.0 时遇到了同样的错误: 错误信息如下:

我遇到的错误。

但是当我查看我的`app/Providers/RouteServiceProvider.php`文件时,我发现我的引导方法内有名称空间。然后我只需取消注释这个=> protected $namespace = 'App\\Http\\Controllers';。 现在我的项目可以正常运行。

11

Laravel 8更新了RouteServiceProvider,它会影响到字符串语法的路由。您可以像以前的答案一样进行更改,但推荐的方式是使用“action”语法,而不是使用字符串语法的路由:

Route::get('register', 'Api\RegisterController@register');

它应该被改变为:

Route::get('register', [RegisterController::class, 'register']);

8

Laravel 8文档比这里提供的任何答案都更简明清晰地回答了这个问题:

路由命名空间更新

在之前的Laravel版本中,RouteServiceProvider包含一个$namespace属性。该属性的值会自动添加到控制器路由定义以及对action助手 / URL::action方法的调用中。在Laravel 8.x中,默认情况下,此属性的值为null。这意味着Laravel将不会自动添加任何命名空间前缀。因此,在新的Laravel 8.x应用程序中,应使用标准的PHP可调用语法定义控制器路由:

use App\Http\Controllers\UserController;

Route::get('/users', [UserController::class, 'index']);

action 相关的方法的调用应使用相同的可调用语法:

action([UserController::class, 'index']);

return Redirect::action([UserController::class, 'index']);

如果您喜欢 Laravel 7.x 的控制器路由前缀方式,您可以简单地将 $namespace 属性添加到您的应用程序的 RouteServiceProvider 中。

8

如果您正在使用 Laravel 8,只需复制并粘贴我的代码:

use App\Http\Controllers\UserController;

Route::get('/user', [UserController::class, 'index']);

8

针对这个问题,只需取消注释第29行:

protected $namespace = 'App\\Http\\Controllers';

app\Providers\RouteServiceProvider.php文件中。

取消注释第29行代码


1
这个解决了我的问题,laravel 8.22.1版本的。以上评分很高的都没用。谢谢。 - Alpy
非常好,我很高兴能够帮助你。 - Bruno Garcia
这行代码之前没有注释,在加上注释后问题得到了解决。你能解释一下为什么我们需要在我的情况下添加或删除注释吗?Laravel 版本是 9。 - Billu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接