api路由必须用route::apiresource(),因其自动启用api中间件组、生成5条rest路由并解析json;混用route::resource()会导致419/405错误、空参数及csrf拦截。

API 路由必须用 Route::apiResource(),混用 Route::resource() 是多数 419 / 405 / 空参数问题的根源。
为什么不能在 routes/api.php 里写 Route::resource()
Route::resource() 默认走 web 中间件组:带 session、CSRF 验证、HTML 模板逻辑。API 请求没发 CSRF token,直接 419;它还硬塞 /users/create 和 /users/{user}/edit 两个 HTML 路由,根本不会被前端调用,反而污染路由列表。
-
Route::apiResource('users', UserController::class)→ 生成 5 条路由(index、store、show、update、destroy),自动启用api中间件组(含throttle、substituteBindings),请求体自动解析为 JSON -
Route::resource('users', UserController::class)→ 生成 7 条路由,store()方法里$request->all()拿不到数据,因为默认不解析 JSON body - 哪怕你手动加了
->middleware('api'),CSRF 还是会拦截 POST/PUT/PATCH —— 它不认这个中间件覆盖
控制器方法签名必须严格匹配约定
Laravel 不做类型推断、不校验参数名拼写、不忽略大小写。写错一个字母或加个类型提示,绑定就静默失败。
- 参数名必须是单数且与资源名一致:
users→$user,api_tokens→$apiToken(下划线转驼峰),不能是$id或$userId - 方法必须是
public,不能有static,不能带默认值(如update(Request $request, $user, $force = false)) -
update()必须带Request $request参数,否则 PUT/PATCH 的 JSON body 取不到;destroy()写成delete()就是 404 - 别手写控制器——用
php artisan make:controller Api/V1/UserController --api,它生成的类已删掉create()/edit(),签名全对,连注释都标好了// POST /api/users
嵌套资源必须显式用 shallow()
三级嵌套路由(如 /posts/{post}/comments/{comment})实测响应延迟增加约 30%,且破坏客户端缓存粒度。
- 正确写法:
Route::apiResource('users.posts', PostController::class)->shallow(); - 生成的路由包含
GET /users/{user}/posts和POST /users/{user}/posts,但show、update、destroy落在/posts/{post},避免深度嵌套 - 别依赖自动推导——
shallow()必须显式调用,否则框架照常生成三级 URL - 嵌套层级建议不超过两层;超过时考虑用查询参数替代,比如
GET /comments?post_id=123
API 路由必须收口到 routes/api.php 并加版本前缀
所有 API 路由只能出现在 routes/api.php,且必须用 Route::prefix('v1') 开头。不加前缀等于放弃未来兼容性。
-
routes/api.php已默认启用api中间件组,但你不显式加prefix,后续升级 v2 就得改所有 URL 和前端代码 - 认证路由必须单独分组:
Route::middleware(['auth:sanctum'])->group(function () { ... });公开接口(如/v1/products)不能和私有接口(如/v1/user)混在同一 group 里 - 别在
routes/web.php里写任何 API 路由——哪怕只有一条,也会导致中间件冲突、CSRF 错误、日志混乱 - 资源路由优先用
apiResource()+shallow(),别手动写七条Route::get()/Route::post()—— 易漏、难维护、不保 REST 语义
最易被忽略的是控制器方法参数名和路由绑定的严格性:框架只认 $user,不认 $id 或 $userId,也不报错,只是让 $user 始终为 null —— 这种静默失败比 500 更难排查。











