Laravel HTTP Request

访问 Request 实例

要通过依赖注入获得当前HTTP请求的实例,我们应该在控制器方法上键入Illuminate\Http\Request类的类型限定。 传入的请求实例将由Service Container自动注入:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Store a new user.
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }
}

依赖注入和路由参数

如果我们的控制器方法也期望从路由参数获取值,则应在其他依赖项之后列出路由参数。 例如,如果我们的路由是这样定义的:

Route::put('user/{id}', 'UserController@update');

然后我们可以使用下面的代码,同样还是指定一个Request 实例,然后在后面跟着参数id

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * Update the specified user.
     *
     * @param  Request  $request
     * @param  string  $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

在路由的闭包中使用Request实例

有时候我们想在路由的闭包中使用Request实例。这也是可以的,在方法的参数中使用Request作为一个类型限定,在方法体中就可以使用了

use Illuminate\Http\Request;

Route::get('/', function (Request $request) {
    //
});

请求路径 与 方法

Illuminate\Http\Request实例提供了多种方法来检查应用程序的HTTP请求,并且继承了Symfony\Component\HttpFoundation\Request类。我们将在下面讨论一些最重要的方法。

检索请求路径

可以使用Request实例的path方法来检索请求的路径。path方法返回请求的路径信息。因此,如果传入请求的地址是http://domain.com/foo/bar,则path方法将返回foo/bar

$uri = $request->path();

is方法使我们可以验证传入的请求路径是否与给定的模式匹配。使用此方法时,可以将字符*用作通配符以匹配任意的字串:

if ($request->is('admin/*')) {
    //
}

检索请求URL

要检索传入请求的完整URL,可以使用url或fullUrl方法。该url方法将返回不含查询字符串的URL,而该fullUrl方法包含查询字符串:

// Without Query String...
$url = $request->url();

// With Query String...
$url = $request->fullUrl();

检索请求方法

method方法将返回请求的HTTP动词。我们可以使用isMethod方法来验证HTTP动词是否与给定的字符串匹配:

$method = $request->method();

if ($request->isMethod('post')) {
    //
}

PSR7 请求

Laravel中为HTTP的消息,包括请求和响应,按照PSR-7标准定义了相应的接口。如果要获取PSR-7请求的实例而不是Laravel请求,则首先需要安装一些库。Laravel使用Symfony HTTP消息组件将典型的Laravel请求和响应转换为PSR-7标准的实现:

$ composer require symfony/psr-http-message-bridge
$ composer require nyholm/psr7

一旦安装了这些库,就可以通过在路由闭包或控制器方法上指定请求接口的类型来获取符合PSR-7标准的请求:

use Psr\Http\Message\ServerRequestInterface;

Route::get('/', function (ServerRequestInterface $request) {
    //
});

如果从路由或控制器返回PSR-7响应实例,它将自动转换回Laravel响应实例并由框架显示。


过滤输入

默认情况下,Laravel在应用程序的全局中间件堆栈中包含了TrimStringsConvertEmptyStringsToNull中间件。这些中间件在App\Http\Kernel类的堆栈中列出。这些中间件将自动对请求中的所有传入字符串字段进行整理,并将所有空字符串字段转换为null。这使我们不必这些规范化问题。

如果要禁用这些行为,可以通过从App\Http\Kernel 类的$middleware属性中删除这两个中间件。


检索输入

检索所有输入数据

我们也可以使用Request的all方法检索所有输入数据,并将这些数据存储成数组返回给一个变量:

$input = $request->all();

检索输入值

我们可以使用一些简单的方法,来获取Illuminate\Http\Request实例中的所有用户输入,该方法使我们不用关心此次HTTP请求是使用哪种请求动词。不管HTTP动词是什么,input方法都可用于检索用户输入:

$name = $request->input('name');

我们给input方法的设定第二个参数作为默认值。如果请求中没有要检索的值,则将返回第二个参数的值:

$name = $request->input('name', 'Sally');

当使用包含数组输入的表单时,请使用“.”符号来访问数组:

$name = $request->input('products.0.name');

$names = $request->input('products.*.name');

input也可以不带任何参数,以便将所有输入值返回为关联数组:

$input = $request->input();

从Query String中检索输入

input方法从整个请求(包括Query String)中检索值,query方法将仅从Query String中检索值:

$name = $request->query('name');

如果请求的Query String中值不存在,则将返回此方法的第二个参数:

$name = $request->query('name', 'Helen');

query可以不带任何参数,和input方法一样,返回一个关联数组:

$query = $request->query();

通过动态属性检索输入

我们还可以使用Illuminate\Http\Request实例上的动态属性访问用户输入。例如,如果应用程序表单包含一个name字段,则可以像下面这样访问该字段的值:

$name = $request->name;

使用动态属性时,Laravel将首先在整个请求消息中(包括请求地址和body体)查找参数的值。如果不存在,Laravel将在路径参数中搜索该字段。

检索JSON输入值

将JSON请求发送到应用程序时,只要请求的Content-Type正确设置为application/json,就可以通过input方法获取到相应的数据。也可以使用“.”访问JSON的某个字段值:

$name = $request->input('user.name');

检索布尔输入值

当处理诸如复选框之类的HTML元素时,应用程序可能会收到实际上是字符串的“true”值。例如,“ true”或“ on”。为了方便起见,我们可以使用boolean方法以布尔值形式检索这些值。boolean方法会将1,“ 1”,true,“ true”,“ on”和“ yes”这些值转成布尔值true。所有其他值将返回false:

$archived = $request->boolean('archived');

检索输入数据的一部分

如果需要检索输入数据的子集,则可以使用onlyexcept方法。这两种方法都接受单个array或动态的参数列表:

$input = $request->only(['username', 'password']);

$input = $request->only('username', 'password');

$input = $request->except(['credit_card']);

$input = $request->except('credit_card');

检查是否存在输入值

我们应该使用has方法来确定请求中是否存在值。如果请求中存在该值,则has方法返回true:

if ($request->has('name')) {
    //
}

当给定一个数组时,has方法将检查是否存在所有指定的值:

if ($request->has(['name', 'email'])) {
    //
}

如果指定的值中存在任意一个,则hasAny方法返回true:

if ($request->hasAny(['name', 'email'])) {
    //
}

如果要确定请求中是否存在一个值并且该值不为空,则可以使用以下filled方法:

if ($request->filled('name')) {
    //
}

要确定请求中是否缺少指定的键,可以使用以下missing方法:

if ($request->missing('name')) {
    //
}

旧的输入

Laravel允许在下一个请求期间保留来自上一个请求的输入。此功能对于在检测到验证错误后重新填充表单方面特别有用。但是,如果我们正在使用Laravel包含的验证功能,则不太可能需要这些方法,因为Laravel的某些内置验证工具会自动调用它们。

将输入放到到session中

Illuminate\Http\Request类的flash方法可以将输入暂时保存到session中,以便用户的下一个请求可以获取到这些数据:

$request->flash();

我们也可以使用flashOnlyflashExcept方法将请求数据的子集刷新到会话中。这些方法对于将敏感信息(例如密码)保留在会话之外非常有用:

$request->flashOnly(['username', 'email']);

$request->flashExcept('password');

存储输入然后重定向

由于我们通常希望先将输入的内容保存到会话中,然后重定向到上一页,因此我们可以使用以下withInput方法轻松地将输入的内容刷新链接到的重定向中:

return redirect('form')->withInput();

return redirect('form')->withInput(
    $request->except('password')
);

检索旧输入

要从上一个请求中检索刷新的输入,可以使用Request实例的old方法。old方法将从会话中获取先前保存的输入数据:

$username = $request->old('username');

Laravel还提供了全局old函数。如果要在Blade模板中显示旧输入,则使用old函数会更加方便。如果给定字段不存在旧输入,将返回null:

<input type="text" name="username" value="{{ old('username') }}">

从请求中获取Cookie

Laravel框架创建的所有cookie均已加密并使用身份验证代码签名,这意味着如果客户端更改了它们,它们将被视为无效。要从请求中获取Cookie值,可以使用Illuminate\Http\Request实例中的cookie方法:

$value = $request->cookie('name');

或者,我们可以使用Cookie Facade访问Cookie值:

use Illuminate\Support\Facades\Cookie;

$value = Cookie::get('name');

将Cookie附加到响应中

我们可以使用Illuminate\Http\Response中的cookie方法将Cookie附加到响应消息中。应该将cookie的名称和值传递给此方法:

return response('Hello World')->cookie(
    'name', 'value', $minutes
);

该cookie方法还接受一些不常使用的参数。通常,这些参数与PHP的setcookie方法具有相同的目的和含义:

return response('Hello World')->cookie(
    'name', 'value', $minutes, $path, $domain, $secure, $httpOnly
);

另外,我们可以使用Cookie Facade将 cookie加入队列,依次附加到应用程序的响应实例中。queue方法接受Cookie实例或创建Cookie实例所需的参数。这些Cookie将在发送到浏览器之前附加到响应实例中:

Cookie::queue(Cookie::make('name', 'value', $minutes));

Cookie::queue('name', 'value', $minutes);

生成Cookie实例

如果我们想生成一个Symfony\Component\HttpFoundation\Cookie实例,以后可以将其提供给响应实例,则可以使用全局函数cookie。除非将它附加到响应实例,否则它将不会将其发送回客户端:

$cookie = cookie('name', 'value', $minutes);

return response('Hello World')->cookie($cookie);

提前使Cookie失效 我们可以通过Cookie的forget方法使cookie过期,从而将其删除:

Cookie::queue(Cookie::forget('name'));

或者,我们可以将过期的Cookie附加到响应实例:

$cookie = Cookie::forget('name');

return response('Hello World')->withCookie($cookie);

Files

检索上传的文件

我们可以使用Illuminate\Http\Request中的file方法或动态属性从实例中访问要上传的文件。file方法返回Illuminate\Http\UploadedFile该类的实例,该实例继承了PHPSplFileInfo类,并提供了多种与文件交互的方法:

$file = $request->file('photo');

$file = $request->photo;

我们可以使用hasFile方法确定文件是否存在于请求中:

if ($request->hasFile('photo')) {
    //
}

验证成功上传

除了检查文件是否存在之外,还可以使用isValid方法验证上传的文件是否有效:

if ($request->file('photo')->isValid()) {
    //
}

文件路径和扩展名

UploadedFile类还包含用于访问文件的完整的路径和扩展的方法。extension方法将尝试根据其内容来推断文件的扩展名。此扩展名可能与客户端提供的扩展名不同:

$path = $request->photo->path();

$extension = $request->photo->extension();

其他文件方法

UploadedFile实例上还有许多其他可用的方法。请查阅该类的API文档,以获取有关这些方法的更多信息。

存储上传的文件

要存储上传的文件,通常将使用已配置的文件系统之一。UploadedFile 类有一个store方法可以将上传的文件移动到磁盘中的指定目录下,它可以是本地文件系统的中某个位置,也可以是像亚马逊S3上的云存储的位置。

store方法接受文件系统配置的一个绝对路径作为存储文件的路径。该路径不应包含文件名,因为将自动生成一个唯一的ID作为文件名。

store方法还有第二个参数,用于指定存储文件的磁盘名称。该方法将返回文件相对于磁盘根目录的路径:

$path = $request->photo->store('images');

$path = $request->photo->store('images', 's3');

如果我们不希望自动生成文件名,则可以使用storeAs方法,该方法接受路径,文件名和磁盘名作为其参数:

$path = $request->photo->storeAs('images', 'filename.jpg');

$path = $request->photo->storeAs('images', 'filename.jpg', 's3');

配置受信任的代理

在终止TLS/SSL证书的负载均衡器后面运行应用程序时,我们可能会注意到应用程序有时不生成HTTPS链接。通常,这是因为正在从80端口上的负载均衡器转发应用程序的流量,不知道它应该生成安全链接。

要解决此问题,我们可以使用App\Http\Middleware\TrustProxiesLaravel应用程序中包含的中间件,该中间件可以快速自定义应由应用程序信任的负载均衡器或代理。受信任代理应作为$proxies此中间件属性上的数组列出。除了配置受信任的代理之外,还可以配置$headers应受信任的代理:

<?php

namespace App\Http\Middleware;

use Fideloper\Proxy\TrustProxies as Middleware;
use Illuminate\Http\Request;

class TrustProxies extends Middleware
{
    /**
     * The trusted proxies for this application.
     *
     * @var string|array
     */
    protected $proxies = [
        '192.168.1.1',
        '192.168.1.2',
    ];

    /**
     * The headers that should be used to detect proxies.
     *
     * @var int
     */
    protected $headers = Request::HEADER_X_FORWARDED_ALL;
}

如果我们使用的是AWS Elastic Load Balancing,则$headers值应为Request::HEADER_X_FORWARDED_AWS_ELB。有关该$headers属性中可能使用的常量的更多信息,请查阅Symfony的有关信任代理的文档。

信任所有代理

如果我们使用的是Amazon AWS或其他“云”负载均衡器,则可能不知道实际负载的IP地址。在这种情况下,我们可以用*来信任所有代理:

/**
 * The trusted proxies for this application.
 *
 * @var string|array
 */
protected $proxies = '*';

查看笔记

扫码一下
查看教程更方便