遇到了一个奇怪的 Request 问题

问题: 自己创建了TestRequest 类去继承 Illuminate\Http\Request 在Controller 中去use TestRequest
在Controller 取不到值 下面是代码

TestRequest:

<?php
namespace App\Http\Requests\Course;

use Illuminate\Http\Request;

class TestRequest extends Request
{

}

Controller:

<?php

namespace App\Http\Controllers\Api\Course;

use App\Http\Controllers\Controller;
use App\Http\Requests\Course\TestRequest;

class ElectiveController extends Controller
{

  /**
 * 选修课列表
 * @param TestRequest $request
 */
 public function index(TestRequest $request)
 {  
       $token = $request->get('token');
      dd($request);
  }

}

token的打印:

null

request的打印:

遇到了一个奇怪的 Request 问题

我试了一下 直接在Controller 中继承 Illuminate\Http\Request 是可以取到值的

我的想法是 在初始化的时候有问题 所以里面的都是null

我也尝试了 直接让TestReques继承 Illuminate\Foundation\Http\FormRequest; 是可以取到值的

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
最佳答案

奥秘在入口文件public/index.php

// 根据已经注册到容器中的接口获取Http处理核心的实例
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// 通过Http处理核心的handle处理请求
$response = $kernel->handle(
// 传入请求快照
    $request = Illuminate\Http\Request::capture()
);

// 输出响应
$response->send();

// 响应后续处理,terminate中间件
$kernel->terminate($request, $response);

Illuminate\Http\Request::capture()方法会调用SymfonyRequest,获取解析之后的请求对象,大部分请求参数的解析操作在SymfonyRequest类里面实现,有兴趣可以查看下createFromGlobals方法的实现

public static function capture()
{
    static::enableHttpMethodParameterOverride();

    return static::createFromBase(SymfonyRequest::createFromGlobals());
}

再回到HttpKernelhandle方法,这个方法里面就把传入的request对象注册到了服务容器中

public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();

        // 这里再次传递了request
        $response = $this->sendRequestThroughRouter($request);
    } catch (Exception $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        $this->reportException($e = new FatalThrowableError($e));

        $response = $this->renderException($request, $e);
    }

    $this->app['events']->dispatch(
        new Events\RequestHandled($request, $response)
    );

    return $response;
}

查看$this->sendRequestThroughRouter($request)方法

protected function sendRequestThroughRouter($request)
{
    // 秘密就在这,这里把request实例对象注册到了服务容器的request key上
    $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}

那么为什么可以通过Illuminate\Http\Request获取到这个request对象?
那就需要看一下服务容器是怎么注册Illuminate\Http\Request的,这里找了半天没找到相关的代码,然后我就把dd(app())出来看了一下,发现服务容器的aliasesabstractAliases有建立Illuminate\Http\Requestrequest的映射,然后在服务容器的初始化方法里看到有调用注册abstractAliases的方法

// 服务容器构造方法
public function __construct($basePath = null)
{
    if ($basePath) {
        $this->setBasePath($basePath);
    }

    $this->registerBaseBindings();
    $this->registerBaseServiceProviders();
    // 这里注册了aliases
    $this->registerCoreContainerAliases();
}

registerCoreContainerAliases方法会看到一个二维数组,二维数组里面就定义了一系列的类别名,可以看到这里把request作为Illuminate\Http\RequestSymfony\Component\HttpFoundation\Request的别名,这样就把这两个类绑定到了app('request'),进而可以获取到之前注册给request键的request对象实例

public function registerCoreContainerAliases()
{
    foreach ([
        ...省略其他
        'request'              => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
        ...省略其他
    ] as $key => $aliases) {
        foreach ($aliases as $alias) {
            $this->alias($key, $alias);
        }
    }
}

现在你就明白了,直接继承Request是不行的,你需要通过一种机制去调用Illuminate\Http\Request::capture(),这个方法返回的才是你所需要的

4年前 评论
讨论数量: 3

奥秘在入口文件public/index.php

// 根据已经注册到容器中的接口获取Http处理核心的实例
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// 通过Http处理核心的handle处理请求
$response = $kernel->handle(
// 传入请求快照
    $request = Illuminate\Http\Request::capture()
);

// 输出响应
$response->send();

// 响应后续处理,terminate中间件
$kernel->terminate($request, $response);

Illuminate\Http\Request::capture()方法会调用SymfonyRequest,获取解析之后的请求对象,大部分请求参数的解析操作在SymfonyRequest类里面实现,有兴趣可以查看下createFromGlobals方法的实现

public static function capture()
{
    static::enableHttpMethodParameterOverride();

    return static::createFromBase(SymfonyRequest::createFromGlobals());
}

再回到HttpKernelhandle方法,这个方法里面就把传入的request对象注册到了服务容器中

public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();

        // 这里再次传递了request
        $response = $this->sendRequestThroughRouter($request);
    } catch (Exception $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        $this->reportException($e = new FatalThrowableError($e));

        $response = $this->renderException($request, $e);
    }

    $this->app['events']->dispatch(
        new Events\RequestHandled($request, $response)
    );

    return $response;
}

查看$this->sendRequestThroughRouter($request)方法

protected function sendRequestThroughRouter($request)
{
    // 秘密就在这,这里把request实例对象注册到了服务容器的request key上
    $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}

那么为什么可以通过Illuminate\Http\Request获取到这个request对象?
那就需要看一下服务容器是怎么注册Illuminate\Http\Request的,这里找了半天没找到相关的代码,然后我就把dd(app())出来看了一下,发现服务容器的aliasesabstractAliases有建立Illuminate\Http\Requestrequest的映射,然后在服务容器的初始化方法里看到有调用注册abstractAliases的方法

// 服务容器构造方法
public function __construct($basePath = null)
{
    if ($basePath) {
        $this->setBasePath($basePath);
    }

    $this->registerBaseBindings();
    $this->registerBaseServiceProviders();
    // 这里注册了aliases
    $this->registerCoreContainerAliases();
}

registerCoreContainerAliases方法会看到一个二维数组,二维数组里面就定义了一系列的类别名,可以看到这里把request作为Illuminate\Http\RequestSymfony\Component\HttpFoundation\Request的别名,这样就把这两个类绑定到了app('request'),进而可以获取到之前注册给request键的request对象实例

public function registerCoreContainerAliases()
{
    foreach ([
        ...省略其他
        'request'              => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
        ...省略其他
    ] as $key => $aliases) {
        foreach ($aliases as $alias) {
            $this->alias($key, $alias);
        }
    }
}

现在你就明白了,直接继承Request是不行的,你需要通过一种机制去调用Illuminate\Http\Request::capture(),这个方法返回的才是你所需要的

4年前 评论

authorize 方法返回 false

4年前 评论
leo
4年前 评论
largezhou 4年前
whcoding (楼主) 4年前

奥秘在入口文件public/index.php

// 根据已经注册到容器中的接口获取Http处理核心的实例
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

// 通过Http处理核心的handle处理请求
$response = $kernel->handle(
// 传入请求快照
    $request = Illuminate\Http\Request::capture()
);

// 输出响应
$response->send();

// 响应后续处理,terminate中间件
$kernel->terminate($request, $response);

Illuminate\Http\Request::capture()方法会调用SymfonyRequest,获取解析之后的请求对象,大部分请求参数的解析操作在SymfonyRequest类里面实现,有兴趣可以查看下createFromGlobals方法的实现

public static function capture()
{
    static::enableHttpMethodParameterOverride();

    return static::createFromBase(SymfonyRequest::createFromGlobals());
}

再回到HttpKernelhandle方法,这个方法里面就把传入的request对象注册到了服务容器中

public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();

        // 这里再次传递了request
        $response = $this->sendRequestThroughRouter($request);
    } catch (Exception $e) {
        $this->reportException($e);

        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        $this->reportException($e = new FatalThrowableError($e));

        $response = $this->renderException($request, $e);
    }

    $this->app['events']->dispatch(
        new Events\RequestHandled($request, $response)
    );

    return $response;
}

查看$this->sendRequestThroughRouter($request)方法

protected function sendRequestThroughRouter($request)
{
    // 秘密就在这,这里把request实例对象注册到了服务容器的request key上
    $this->app->instance('request', $request);

    Facade::clearResolvedInstance('request');

    $this->bootstrap();

    return (new Pipeline($this->app))
                ->send($request)
                ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
                ->then($this->dispatchToRouter());
}

那么为什么可以通过Illuminate\Http\Request获取到这个request对象?
那就需要看一下服务容器是怎么注册Illuminate\Http\Request的,这里找了半天没找到相关的代码,然后我就把dd(app())出来看了一下,发现服务容器的aliasesabstractAliases有建立Illuminate\Http\Requestrequest的映射,然后在服务容器的初始化方法里看到有调用注册abstractAliases的方法

// 服务容器构造方法
public function __construct($basePath = null)
{
    if ($basePath) {
        $this->setBasePath($basePath);
    }

    $this->registerBaseBindings();
    $this->registerBaseServiceProviders();
    // 这里注册了aliases
    $this->registerCoreContainerAliases();
}

registerCoreContainerAliases方法会看到一个二维数组,二维数组里面就定义了一系列的类别名,可以看到这里把request作为Illuminate\Http\RequestSymfony\Component\HttpFoundation\Request的别名,这样就把这两个类绑定到了app('request'),进而可以获取到之前注册给request键的request对象实例

public function registerCoreContainerAliases()
{
    foreach ([
        ...省略其他
        'request'              => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
        ...省略其他
    ] as $key => $aliases) {
        foreach ($aliases as $alias) {
            $this->alias($key, $alias);
        }
    }
}

现在你就明白了,直接继承Request是不行的,你需要通过一种机制去调用Illuminate\Http\Request::capture(),这个方法返回的才是你所需要的

4年前 评论

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