控制器必须放在app/http/controllers/下,类名以controller结尾且继承controller基类,命名空间需与目录结构一致;路由须用数组语法[class::class, 'method'],参数绑定需严格匹配;返回json应使用response()->json()。

控制器文件放哪、命名怎么写才不报错
Laravel 会按约定自动加载控制器,路径和类名不对,php artisan route:list 就看不到路由,访问直接 404 或 Class not found。
必须放在 app/Http/Controllers/ 下(Laravel 9+ 默认),子目录可以有,但命名空间得同步。比如 app/Http/Controllers/Admin/UserController.php,对应命名空间就得是 App\Http\Controllers\Admin,不是 App\Http\Controllers。
- 类名必须以
Controller结尾(如UserController),否则Route::get('/user', [User::class, 'index'])会找不到 - 方法名别用下划线,用驼峰(
showProfile可以,show_profile在某些 PHP 版本或严格模式下可能被忽略) - 控制器类必须继承
Controller(use App\Http\Controllers\Controller;),哪怕没用到它的方法——这是 Laravel 路由调度的识别依据
Route::get() 里传数组还是字符串?闭包能替代控制器吗
用数组形式([UserController::class, 'index'])是推荐做法,它支持依赖注入、中间件、缓存路由等机制;字符串形式('UserController@index')在 Laravel 10+ 已被弃用,运行时会抛出 Deprecated: Route string syntax is deprecated。
闭包路由虽然写起来快,但它绕过了控制器生命周期(构造函数注入、中间件执行顺序、请求验证前置等),一旦逻辑变复杂,就难维护、难测试、难复用。
- 别在闭包里写数据库查询或业务逻辑,只做极简跳转或调试用
- 如果控制器方法需要参数(如
show($id)),路由定义里必须显式绑定:Route::get('/user/{id}', [UserController::class, 'show']);,不能漏掉{id} - 参数名必须和方法签名完全一致(
show($userId)但路由写{id}→ 运行时报Missing required parameter)
构造函数里依赖注入失败?$this->middleware() 不生效
控制器构造函数注入失败,八成是忘了在 __construct() 里调 parent::__construct() —— 实际上不用调,Laravel 的 Controller 基类构造函数是空的,问题往往出在:你加了自定义构造函数但没声明 public,或者用了 protected 导致 DI 容器无法实例化。
$this->middleware() 必须在构造函数里调用,且只能在构造函数中注册;写在方法里(比如 index() 中)完全无效。
- 中间件注册要写全类名或字符串,
$this->middleware('auth')可以,$this->middleware(Authenticate::class)也可以,但别写成$this->middleware('App\Http\Middleware\Authenticate')(带命名空间的字符串在 Laravel 9+ 默认不支持) - 想对某个方法单独加中间件?用数组语法:
$this->middleware('throttle:60,1')->only('store'); - 构造函数里别做耗时操作(如 DB 查询),它会在每次请求控制器前执行,哪怕最终没调用任何方法
控制器里返回 JSON 却带 HTML 模板?Response 类怎么选
用 return response()->json(...) 是最稳的,明确告诉框架“我要 JSON”,不会受视图配置或全局中间件影响。而直接 return ['data' => ...] 看似简洁,但在启用了 Illuminate\Routing\Middleware\SubstituteBindings 或某些 API 资源中间件时,可能被意外包装成响应对象,甚至触发视图渲染(尤其当 APP_DEBUG=false 时更难排查)。
- API 控制器建议继承
ApiController(自己建个基类),统一设置Accept: application/json处理逻辑 - 别在控制器里用
view()返回页面的同时又返回json(),Laravel 不会自动判断格式,客户端拿不到预期类型 -
response()->download()和response()->stream()这类特殊响应,记得手动设Content-Type和Content-Disposition,不然浏览器可能乱解析
控制器不是万能胶,它只该处理请求分发、参数整理、响应组装这三件事。业务逻辑越往 service 层抽,后面改接口、加缓存、写单元测试就越省力——这点容易被赶工期时跳过,但真出问题,最先卡住的就是控制器里塞太满的代码。











