新增加的路由文件接口出问题

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

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

            // admin路由定义
            Route::prefix('admin')
                ->namespace($this->namespace . '\\Admin')
                ->group(base_path('routes/admin.php'));

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

路由

新增加的路由文件接口出问题

public function update(RoleRequest $roleRequest, Role $role)
{
    dd($role);
    $role->update(['name' => $roleRequest->input('name')]);
    $role->hasPermissions()->sync($roleRequest->input('permission_ids'));
    return Show::success('修改成功');
}

结果如下

![新增加的路由文件接口出问题]
新增加的路由文件接口出问题

public function update(RoleRequest $roleRequest, $id)
{  // 换成 $id
    dd($id);
    $role->update(['name' => $roleRequest->input('name')]);
    $role->hasPermissions()->sync($roleRequest->input('permission_ids'));
    return Show::success('修改成功');
}

结果如下
新增加的路由文件接口出问题

之前用 api.php 都是正常的,新增了admin.php文件就成这种情况了

《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
最佳答案

php artisan route:list 看看生成的路由是啥

1年前 评论
Su (作者) 1年前
王大牛 (楼主) 1年前
Su (作者) 1年前
王大牛 (楼主) 1年前
laravel_peng 1年前
王大牛 (楼主) 1年前
讨论数量: 20
laravel_peng

类似于 restful 类型的接口接 put/patch 收不到

有报错信息么?

1年前 评论
王大牛 (楼主) 1年前
laravel_peng (作者) 1年前
王大牛 (楼主) 1年前
王大牛 (楼主) 1年前
laravel_peng (作者) 1年前
王大牛 (楼主) 1年前

php artisan route:list 看看生成的路由是啥

1年前 评论
Su (作者) 1年前
王大牛 (楼主) 1年前
Su (作者) 1年前
王大牛 (楼主) 1年前
laravel_peng 1年前
王大牛 (楼主) 1年前
DonnyLiu

建议贴下报错信息出来

1年前 评论

file

1年前 评论
王大牛 (楼主) 1年前

update 需要加条件id

1年前 评论
王大牛 (楼主) 1年前

正如 @Su 所说,问题出在定义 admin 路由时没有加中间件 api

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

为什么要加 middleware('api'),它帮你做了什么?

因为在 $middlewareGroups 中,'api' 中定义了 SubstituteBundings:class,它帮你实现了依赖注入

'api' => [
    // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
    'throttle:api',
    \Illuminate\Routing\Middleware\SubstituteBindings::class, // this line
],

具体实现在 SubstituteBindingshandle() 中的 $this->router->substituteImplicitBindings($route)

try {
    $this->router->substituteBindings($route = $request->route());

    $this->router->substituteImplicitBindings($route);
} catch (ModelNotFoundException $exception) {

这里 $this->routerRegistrar 接口类具体实现是 Router

所以 substituteImplicitBindings() 的实现类是 Router

public function substituteImplicitBindings($route)
{
    ImplicitRouteBinding::resolveForRoute($this->container, $route);
}

又跳到了 ImplicitRouteBinding::resolveForRoute() 静态方法。

该方法很长,大体上可以看成三步:

  1. 通过反射拿到签名参数,也就是 RoleController@update(Request $request, Role $role) 中的 Role $role

    source code

     foreach ($route->signatureParameters(['subClass' => UrlRoutable::class]) as $parameter) {

    signatureParameters() 会跳到 RouteSignatureParameters::FromAction()

    FromAction() 比较绕,但对于此处还是比较好理解:

    它从 $route->action['uses'] 中拿到回调字符串 App\Http\Controller\RoleController@update

    再利用 (new ReflectionFunction($callback))->getParameters() 拿到参数

    最后在 ! empty($conditions['subClass']) => array_filter($parameters, fn ($p) => Reflector::isParameterSubclassOf($p, $conditions['subClass'])), 中将实现 UrlRoutable::class 的类返回

    Model 实现了 UrlRoutable::class,而 Request 没有实现,所以这里只会返回 Role 的参数

    最后得到的 $parameter 大概长这样:

     ReflectionParameter {
         name: "role"
         position: 0
         typeHint: "App\Model\Role"
     }
  2. 通过反射实例化 Model,也就是 Role

    source code

     $instance = $container->make(Reflector::getParameterClassName($parameter));
  1. 查询数据库,并绑定到路由上

    source code

     // 默认 Role 没有软删除,所以返回 `resolveRouteBinding`
     $routeBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
                 ? 'resolveSoftDeletableRouteBinding'
                 : 'resolveRouteBinding';
    
     ...
    
     } elseif (! $model = $instance->{$routeBindingMethod}($parameterValue, $route->bindingFieldFor($parameterName))) {

    $instance->{$routeBindingMethod}($parameterValue, $route->bindingFieldFor($parameterName)) 可以看成是 $role->resolveRouteBinding(2, null)

    Model 中有对 resolveRouteBinding() 的实现:

    source code

     public function resolveRouteBinding($value, $field = null)
     {
         return $this->resolveRouteBindingQuery($this, $value, $field)->first();
     }

    resolveRouteBindingQuery() 就是一个 where 查询:

    source code

     public function resolveRouteBindingQuery($query, $value, $field = null)
     {
         return $query->where($field ?? $this->getRouteKeyName(), $value);
     }

    最后将查询到的结果绑定到 Route 的参数上

    source code

     $route->setParameter($parameterName, $model);
1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!