Skip to content

HTTP 请求

访问请求

要通过依赖注入获取当前 HTTP 请求的实例,您应该在控制器方法中类型提示 Illuminate\Http\Request 类。传入的请求实例将由服务容器自动注入:

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 存储新用户。
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }
}

依赖注入和路由参数

如果您的控制器方法还期望从路由参数中获取输入,您应该在其他依赖项之后列出路由参数。例如,如果您的路由定义如下:

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

您仍然可以类型提示 Illuminate\Http\Request 并通过如下定义控制器方法来访问路由参数 id

php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 更新指定用户。
     *
     * @param  Request  $request
     * @param  string  $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

通过路由闭包访问请求

您还可以在路由闭包上类型提示 Illuminate\Http\Request 类。服务容器将在闭包执行时自动注入传入的请求:

php
use Illuminate\Http\Request;

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

请求路径和方法

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

检索请求路径

path 方法返回请求的路径信息。因此,如果传入请求的目标是 http://domain.com/foo/bar,则 path 方法将返回 foo/bar

php
$uri = $request->path();

is 方法允许您验证传入请求路径是否与给定模式匹配。您可以在使用此方法时使用 * 字符作为通配符:

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

检索请求 URL

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

php
// 不带查询字符串...
$url = $request->url();

// 带查询字符串...
$url = $request->fullUrl();

检索请求方法

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

php
$method = $request->method();

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

PSR-7 请求

PSR-7 标准指定了 HTTP 消息的接口,包括请求和响应。如果您希望获取 PSR-7 请求的实例而不是 Laravel 请求,您首先需要安装一些库。Laravel 使用 Symfony HTTP Message Bridge 组件将典型的 Laravel 请求和响应转换为 PSR-7 兼容的实现:

php
composer require symfony/psr-http-message-bridge
composer require zendframework/zend-diactoros

安装这些库后,您可以通过在路由闭包或控制器方法上类型提示请求接口来获取 PSR-7 请求:

php
use Psr\Http\Message\ServerRequestInterface;

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

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

输入修剪和标准化

默认情况下,Laravel 在应用程序的全局中间件堆栈中包含 TrimStringsConvertEmptyStringsToNull 中间件。这些中间件由 App\Http\Kernel 类列在堆栈中。这些中间件将自动修剪请求中所有传入的字符串字段,并将任何空字符串字段转换为 null。这使您不必在路由和控制器中担心这些标准化问题。

如果您想禁用此行为,可以通过从 App\Http\Kernel 类的 $middleware 属性中删除这两个中间件来将其从应用程序的中间件堆栈中移除。

检索输入

检索所有输入数据

您还可以使用 all 方法将所有输入数据作为 array 检索:

php
$input = $request->all();

检索输入值

使用一些简单的方法,您可以从 Illuminate\Http\Request 实例中访问所有用户输入,而无需担心请求使用了哪个 HTTP 动词。无论 HTTP 动词如何,input 方法都可以用来检索用户输入:

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

您可以将默认值作为 input 方法的第二个参数传递。如果请求的输入值不存在于请求中,则将返回此值:

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

在处理包含数组输入的表单时,使用“点”符号访问数组:

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

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

您可以在不传递任何参数的情况下调用 input 方法,以便将所有输入值作为关联数组检索:

php
$input = $request->input();

从查询字符串中检索输入

虽然 input 方法从整个请求负载(包括查询字符串)中检索值,但 query 方法将仅从查询字符串中检索值:

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

如果请求的查询字符串值数据不存在,则将返回此方法的第二个参数:

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

您可以在不传递任何参数的情况下调用 query 方法,以便将所有查询字符串值作为关联数组检索:

php
$query = $request->query();

通过动态属性检索输入

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

php
$name = $request->name;

使用动态属性时,Laravel 将首先在请求负载中查找参数的值。如果不存在,Laravel 将在路由参数中查找该字段。

检索 JSON 输入值

在向应用程序发送 JSON 请求时,只要请求的 Content-Type 头正确设置为 application/json,您就可以通过 input 方法访问 JSON 数据。您甚至可以使用“点”语法深入到 JSON 数组中:

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

检索输入数据的一部分

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

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

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

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

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

only 方法返回您请求的所有键/值对;然而,它不会返回请求中不存在的键/值对。

确定输入值是否存在

您应该使用 has 方法来确定请求中是否存在某个值。has 方法在请求中存在该值时返回 true

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

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

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

如果您想确定请求中是否存在某个值且不为空,可以使用 filled 方法:

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

旧输入

Laravel 允许您在下一个请求期间保留来自一个请求的输入。此功能在检测到验证错误后重新填充表单时特别有用。然而,如果您使用 Laravel 的验证功能,则不太可能需要手动使用这些方法,因为 Laravel 的一些内置验证设施会自动调用它们。

将输入闪存到会话

Illuminate\Http\Request 类上的 flash 方法将当前输入闪存到会话,以便在用户的下一个请求期间可用:

php
$request->flash();

您还可以使用 flashOnlyflashExcept 方法将请求数据的子集闪存到会话中。这些方法对于将密码等敏感信息排除在会话之外非常有用:

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

$request->flashExcept('password');

闪存输入然后重定向

由于您通常希望将输入闪存到会话中,然后重定向到上一页,您可以轻松地将输入闪存链接到重定向,使用 withInput 方法:

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

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

检索旧输入

要从上一个请求中检索闪存的输入,请在 Request 实例上使用 old 方法。old 方法将从会话中提取先前闪存的输入数据:

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

Laravel 还提供了一个全局 old 辅助函数。如果您在Blade 模板中显示旧输入,使用 old 辅助函数更为方便。如果给定字段没有旧输入,将返回 null

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

Cookies

从请求中检索 Cookies

Laravel 框架创建的所有 cookies 都经过加密并带有身份验证代码签名,这意味着如果客户端更改了它们,它们将被视为无效。要从请求中检索 cookie 值,请在 Illuminate\Http\Request 实例上使用 cookie 方法:

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

或者,您可以使用 Cookie facade 访问 cookie 值:

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

将 Cookies 附加到响应

您可以使用 cookie 方法将 cookie 附加到传出的 Illuminate\Http\Response 实例。您应该将名称、值和 cookie 应被视为有效的分钟数传递给此方法:

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

cookie 方法还接受一些不太常用的参数。通常,这些参数与传递给 PHP 的原生 setcookie 方法的参数具有相同的目的和含义:

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

或者,您可以使用 Cookie facade 将 cookies "排队" 附加到应用程序的传出响应。queue 方法接受一个 Cookie 实例或创建 Cookie 实例所需的参数。这些 cookies 将在发送到浏览器之前附加到传出的响应:

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

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

如果您希望生成一个 Symfony\Component\HttpFoundation\Cookie 实例,可以在稍后时间传递给响应实例,您可以使用全局 cookie 辅助函数。除非将此 cookie 附加到响应实例,否则它不会发送回客户端:

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

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

文件

检索上传的文件

您可以使用 Illuminate\Http\Request 实例上的 file 方法或动态属性访问上传的文件。file 方法返回一个 Illuminate\Http\UploadedFile 类的实例,该类扩展了 PHP 的 SplFileInfo 类,并提供了多种与文件交互的方法:

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

$file = $request->photo;

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

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

验证上传成功

除了检查文件是否存在,您还可以通过 isValid 方法验证上传文件时是否没有问题:

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

文件路径和扩展名

UploadedFile 类还包含用于访问文件的完全限定路径及其扩展名的方法。extension 方法将尝试根据文件内容猜测文件的扩展名。此扩展名可能与客户端提供的扩展名不同:

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

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

其他文件方法

UploadedFile 实例上还有多种其他方法。有关这些方法的更多信息,请查看 API 文档

存储上传的文件

要存储上传的文件,您通常会使用配置的文件系统之一。UploadedFile 类具有一个 store 方法,该方法会将上传的文件移动到您的磁盘之一,该磁盘可以是本地文件系统上的位置,甚至是像 Amazon S3 这样的云存储位置。

store 方法接受相对于文件系统配置根目录的路径。此路径不应包含文件名,因为将自动生成唯一 ID 作为文件名。

store 方法还接受一个可选的第二个参数,用于指定应使用哪个磁盘存储文件。该方法将返回相对于磁盘根目录的文件路径:

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

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

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

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

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

配置可信代理

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

为了解决这个问题,您可以使用 Laravel 应用程序中包含的 App\Http\Middleware\TrustProxies 中间件,该中间件允许您快速自定义应用程序应信任的负载均衡器或代理。您的可信代理应作为数组列在此中间件的 $proxies 属性中。除了配置可信代理,您还可以配置应信任的代理 $headers

php
<?php

namespace App\Http\Middleware;

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

class TrustProxies extends Middleware
{
    /**
     * 应用程序的可信代理。
     *
     * @var array
     */
    protected $proxies = [
        '192.168.1.1',
        '192.168.1.2',
    ];

    /**
     * 应用于检测代理的头。
     *
     * @var string
     */
    protected $headers = Request::HEADER_X_FORWARDED_ALL;
}
lightbulb

如果您使用 AWS 弹性负载均衡,您的 $headers 值应为 Request::HEADER_X_FORWARDED_AWS_ELB。有关可以在 $headers 属性中使用的常量的更多信息,请查看 Symfony 关于信任代理的文档。

信任所有代理

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

php
/**
 * 应用程序的可信代理。
 *
 * @var array
 */
protected $proxies = '*';