跳至内容

HTTP 请求

介绍

Laravel 的Illuminate\Http\Request类提供了一种面向对象的方式来与应用程序正在处理的当前 HTTP 请求进行交互,以及检索随请求提交的输入、cookie 和文件。

与请求交互

访问请求

要通过依赖注入获取当前 HTTP 请求的实例,你应该在路由闭包或控制器方法上添加类型Prompts。传入的请求实例将由 Laravel服务容器Illuminate\Http\Request自动注入

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7 
8class UserController extends Controller
9{
10 /**
11 * Store a new user.
12 */
13 public function store(Request $request): RedirectResponse
14 {
15 $name = $request->input('name');
16 
17 // Store the user...
18 
19 return redirect('/users');
20 }
21}

如上所述,你也可以Illuminate\Http\Request在路由闭包中使用类型Prompts。服务容器会在执行时自动将传入的请求注入到闭包中:

1use Illuminate\Http\Request;
2 
3Route::get('/', function (Request $request) {
4 // ...
5});

依赖注入和路由参数

如果你的控制器方法也需要路由参数作为输入,则应该将路由参数列在其他依赖项之后。例如,如果你的路由定义如下:

1use App\Http\Controllers\UserController;
2 
3Route::put('/user/{id}', [UserController::class, 'update']);

您仍然可以通过定义控制器方法来键入PromptsIlluminate\Http\Request并访问路由参数,如下所示:id

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7 
8class UserController extends Controller
9{
10 /**
11 * Update the specified user.
12 */
13 public function update(Request $request, string $id): RedirectResponse
14 {
15 // Update the user...
16 
17 return redirect('/users');
18 }
19}

请求路径、主机和方法

Illuminate\Http\Request实例提供了多种方法来检查传入的 HTTP 请求,并扩展了该类Symfony\Component\HttpFoundation\Request。我们将在下面讨论其中几个最重要的方法。

检索请求路径

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

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

检查请求路径/路由

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

1if ($request->is('admin/*')) {
2 // ...
3}

使用该routeIs方法,您可以确定传入的请求是否与命名路由匹配:

1if ($request->routeIs('admin.*')) {
2 // ...
3}

检索请求 URL

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

1$url = $request->url();
2 
3$urlWithQueryString = $request->fullUrl();

如果您想将查询字符串数据附加到当前 URL,可以调用该fullUrlWithQuery方法。此方法将给定的查询字符串变量数组与当前查询字符串合并:

1$request->fullUrlWithQuery(['type' => 'phone']);

如果您想要获取不带给定查询字符串参数的当前 URL,您可以使用该fullUrlWithoutQuery方法:

1$request->fullUrlWithoutQuery(['type']);

检索请求主机

host您可以通过、httpHost和方法检索传入请求的“主机” schemeAndHttpHost

1$request->host();
2$request->httpHost();
3$request->schemeAndHttpHost();

检索请求方法

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

1$method = $request->method();
2 
3if ($request->isMethod('post')) {
4 // ...
5}

请求标头

Illuminate\Http\Request你可以使用 方法来从实例中检索请求标头header。如果请求中不存在该标头,null则会返回 。但是,该header方法接受一个可选的第二个参数,如果请求中不存在该标头,则会返回该参数:

1$value = $request->header('X-Header-Name');
2 
3$value = $request->header('X-Header-Name', 'default');

hasHeader方法可用于确定请求是否包含给定的标头:

1if ($request->hasHeader('X-Header-Name')) {
2 // ...
3}

为了方便起见,该bearerToken方法可用于从Authorization标头中检索承载令牌。如果不存在这样的标头,则将返回空字符串:

1$token = $request->bearerToken();

请求 IP 地址

ip方法可用于检索向您的应用程序发出请求的客户端的 IP 地址:

1$ipAddress = $request->ip();

如果您想检索包含所有通过代理转发的客户端 IP 地址的 IP 地址数组,可以使用该ips方法。“原始”客户端 IP 地址将位于数组末尾:

1$ipAddresses = $request->ips();

一般来说,IP 地址应被视为不受信任的、用户控制的输入,并且仅用于提供信息目的。

内容协商

Laravel 提供了几种方法,可以通过标头检查传入请求的内容类型Accept。首先,该getAcceptableContentTypes方法将返回一个数组,其中包含请求所接受的所有内容类型:

1$contentTypes = $request->getAcceptableContentTypes();

accepts方法接受一个内容类型数组,true如果请求接受了其中任何一种内容类型,则返回结果。否则,false将返回:

1if ($request->accepts(['text/html', 'application/json'])) {
2 // ...
3}

你可以使用该prefers方法来确定给定内容类型数组中哪种内容类型最符合请求的优先级。如果请求不接受任何提供的内容类型,null则返回:

1$preferred = $request->prefers(['text/html', 'application/json']);

由于许多应用程序仅提供 HTML 或 JSON,因此您可以使用该expectsJson方法快速确定传入请求是否需要 JSON 响应:

1if ($request->expectsJson()) {
2 // ...
3}

PSR-7 请求

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

1composer require symfony/psr-http-message-bridge
2composer require nyholm/psr7

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

1use Psr\Http\Message\ServerRequestInterface;
2 
3Route::get('/', function (ServerRequestInterface $request) {
4 // ...
5});

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

输入

检索输入

检索所有输入数据

array您可以使用该方法检索所有传入请求的输入数据all。无论传入请求来自 HTML 表单还是 XHR 请求,都可以使用此方法:

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

使用该collect方法,您可以将所有传入请求的输入数据检索为集合

1$input = $request->collect();

collect方法还允许您检索传入请求的输入子集作为集合:

1$request->collect('users')->each(function (string $user) {
2 // ...
3});

检索输入值

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

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

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

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

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

1$name = $request->input('products.0.name');
2 
3$names = $request->input('products.*.name');

您可以调用input不带任何参数的方法来检索所有输入值作为关联数组:

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

从查询字符串中检索输入

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

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

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

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

您可以调用query不带任何参数的方法来检索所有查询字符串值作为关联数组:

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

检索 JSON 输入值

向应用程序发送 JSON 请求时,只要将请求标头正确设置为 ,input即可通过 方法访问 JSON 数据。您甚至可以使用“点”语法来检索嵌套在 JSON 数组/对象中的值:Content-Typeapplication/json

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

检索可字符串化的输入值

除了将请求的输入数据作为原语进行检索之外string,您还可以使用该方法将请求数据作为Illuminate\Support\Stringablestring的实例进行检索

1$name = $request->string('name')->trim();

检索整数输入值

要将输入值检索为整数,可以使用该integer方法。该方法将尝试将输入值转换为整数。如果输入不存在或转换失败,它将返回您指定的默认值。这对于分页或其他数字输入特别有用:

1$perPage = $request->integer('per_page');

检索布尔输入值

在处理复选框等 HTML 元素时,您的应用程序可能会收到实际上是字符串的“真”值。例如,“true”或“on”。为了方便起见,您可以使用boolean方法来检索这些值作为布尔值。对于 1、“1”、true、“true”、“on”和“yes”,该boolean方法将返回。true所有其他值将返回false

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

检索数组输入值

可以使用 方法来检索包含数组的输入值array。此方法始终会将输入值转换为数组。如果请求不包含具有给定名称的输入值,则将返回一个空数组:

1$versions = $request->array('versions');

检索日期输入值

为了方便起见,可以使用date方法来检索包含日期/时间的输入值作为 Carbon 实例。如果请求不包含具有给定名称的输入值,null则将返回:

1$birthday = $request->date('birthday');

该方法接受的第二个和第三个参数date可分别用于指定日期的格式和时区:

1$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');

如果输入值存在但格式无效,InvalidArgumentException则会抛出;因此,建议您在调用该date方法之前验证输入。

检索枚举输入值

您还可以从请求中检索与PHP 枚举对应的输入值。如果请求不包含具有给定名称的输入值,或者枚举没有与输入值匹配的后备值,null则将返回。该enum方法接受输入值的名称和枚举类作为其第一和第二个参数:

1use App\Enums\Status;
2 
3$status = $request->enum('status', Status::class);

您还可以提供一个默认值,当值缺失或无效时将返回该默认值:

1$status = $request->enum('status', Status::class, Status::Pending);

如果输入值是与 PHP 枚举对应的值数组,则可以使用该enums方法将值数组检索为枚举实例:

1use App\Enums\Product;
2 
3$products = $request->enums('products', Product::class);

通过动态属性检索输入

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

1$name = $request->name;

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

检索部分输入数据

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

1$input = $request->only(['username', 'password']);
2 
3$input = $request->only('username', 'password');
4 
5$input = $request->except(['credit_card']);
6 
7$input = $request->except('credit_card');

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

输入存在

你可以使用该has方法判断请求中是否存在某个值。该has方法返回true该值是否存在于请求中:

1if ($request->has('name')) {
2 // ...
3}

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

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

如果存在任何指定的值,则hasAny方法返回:true

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

whenHas如果请求中存在值,该方法将执行给定的闭包:

1$request->whenHas('name', function (string $input) {
2 // ...
3});

whenHas如果请求中不存在指定的值,则可以将第二个闭包传递给将执行的方法:

1$request->whenHas('name', function (string $input) {
2 // The "name" value is present...
3}, function () {
4 // The "name" value is not present...
5});

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

1if ($request->filled('name')) {
2 // ...
3}

如果您想确定请求中是否缺少某个值或者该值是否为空字符串,您可以使用该isNotFilled方法:

1if ($request->isNotFilled('name')) {
2 // ...
3}

当给定一个数组时,该isNotFilled方法将确定所有指定的值是否缺失或为空:

1if ($request->isNotFilled(['name', 'email'])) {
2 // ...
3}

如果任何指定值不是空字符串,则anyFilled方法返回:true

1if ($request->anyFilled(['name', 'email'])) {
2 // ...
3}

whenFilled如果请求中存在值并且不是空字符串,则该方法将执行给定的闭包:

1$request->whenFilled('name', function (string $input) {
2 // ...
3});

whenFilled如果指定的值未“填充”,则可以将第二个闭包传递给将执行的方法:

1$request->whenFilled('name', function (string $input) {
2 // The "name" value is filled...
3}, function () {
4 // The "name" value is not filled...
5});

要确定请求中是否缺少给定的键,您可以使用missingwhenMissing方法:

1if ($request->missing('name')) {
2 // ...
3}
4 
5$request->whenMissing('name', function () {
6 // The "name" value is missing...
7}, function () {
8 // The "name" value is present...
9});

合并附加输入

有时您可能需要手动将其他输入合并到请求的现有输入数据中。为此,您可以使用该merge方法。如果给定的输入键已存在于请求中,它将被提供给该方法的数据覆盖merge

1$request->merge(['votes' => 0]);

mergeIfMissing如果请求的输入数据中不存在相应的键,则可以使用该方法将输入合并到请求中:

1$request->mergeIfMissing(['votes' => 0]);

旧输入

Laravel 允许您在下一个请求中保留上一个请求的输入。此功能在检测到验证错误后重新填充表单时特别有用。但是,如果您使用 Laravel 内置的验证功能,则可能无需直接手动使用这些会话输入闪烁方法,因为 Laravel 的一些内置验证功能会自动调用它们。

将输入闪现到会话

flash类上的方法Illuminate\Http\Request当前输入闪现到会话中,以便在用户下次向应用程序发出请求时可用:

1$request->flash();

您还可以使用flashOnlyflashExcept方法将请求数据的一部分刷入会话。这些方法有助于将诸如密码之类的敏感信息保留在会话之外:

1$request->flashOnly(['username', 'email']);
2 
3$request->flashExcept('password');

闪烁输入然后重定向

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

1return redirect('/form')->withInput();
2 
3return redirect()->route('user.create')->withInput();
4 
5return redirect('/form')->withInput(
6 $request->except('password')
7);

检索旧输入

要检索上一次请求中闪现的输入,请old在 的实例上调用 的方法Illuminate\Http\Request。该方法将从会话old中提取先前闪现的输入数据

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

Laravel 还提供了一个全局Helpers。如果您要在Blade 模板old中显示旧输入,则使用该Helpers重新填充表单会更方便。如果给定字段不存在旧输入,则将返回:oldnull

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

曲奇饼

从请求中检索 Cookies

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

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

输入修剪和规范化

默认情况下,Laravel 在应用程序的全局中间件堆栈中包含Illuminate\Foundation\Http\Middleware\TrimStringsIlluminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull中间件。这些中间件会自动修剪请求中所有传入的字符串字段,并将任何空字符串字段转换为null。这样,您就不必担心路由和控制器中的这些规范化问题。

禁用输入规范化

如果您想要为所有请求禁用此行为,您可以通过调用$middleware->remove应用程序bootstrap/app.php文件中的方法从应用程序的中间件堆栈中删除这两个中间件:

1use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
2use Illuminate\Foundation\Http\Middleware\TrimStrings;
3 
4->withMiddleware(function (Middleware $middleware) {
5 $middleware->remove([
6 ConvertEmptyStringsToNull::class,
7 TrimStrings::class,
8 ]);
9})

如果您希望针对应用程序的部分请求禁用字符串修剪和空字符串转换,可以在应用程序文件中使用trimStrings和中间件方法。这两个方法都接受一个闭包数组,这些闭包应返回来指示是否应跳过输入规范化:convertEmptyStringsToNullbootstrap/app.phptruefalse

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->convertEmptyStringsToNull(except: [
3 fn (Request $request) => $request->is('admin/*'),
4 ]);
5 
6 $middleware->trimStrings(except: [
7 fn (Request $request) => $request->is('admin/*'),
8 ]);
9})

文件

检索已上传的文件

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

1$file = $request->file('photo');
2 
3$file = $request->photo;

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

1if ($request->hasFile('photo')) {
2 // ...
3}

验证上传成功

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

1if ($request->file('photo')->isValid()) {
2 // ...
3}

文件路径和扩展名

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

1$path = $request->photo->path();
2 
3$extension = $request->photo->extension();

其他文件方法

实例上还有许多其他可用的方法。有关这些方法的更多信息,UploadedFile请参阅相应类的 API 文档。

存储上传的文件

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

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

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

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

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

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

有关 Laravel 中文件存储的更多信息,请查看完整的文件存储文档

配置受信任的代理

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

为了解决这个问题,你可以启用Illuminate\Http\Middleware\TrustProxiesLaravel 应用程序自带的中间件,这样你就可以快速自定义应用程序应该信任的负载均衡器或代理。你应该使用trustProxies应用程序bootstrap/app.php文件中的中间件方法来指定受信任的代理:

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustProxies(at: [
3 '192.168.1.1',
4 '10.0.0.0/8',
5 ]);
6})

除了配置受信任的代理之外,您还可以配置应该受信任的代理标头:

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustProxies(headers: Request::HEADER_X_FORWARDED_FOR |
3 Request::HEADER_X_FORWARDED_HOST |
4 Request::HEADER_X_FORWARDED_PORT |
5 Request::HEADER_X_FORWARDED_PROTO |
6 Request::HEADER_X_FORWARDED_AWS_ELB
7 );
8})

如果您使用的是 AWS Elastic Load Balancing,则该headers值应为。如果您的负载均衡器使用RFC 7239中的Request::HEADER_X_FORWARDED_AWS_ELB标准标头,则该值应为。有关该值中可能使用的常量的更多信息,请参阅 Symfony 关于信任代理的文档。ForwardedheadersRequest::HEADER_FORWARDEDheaders

信任所有代理

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

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustProxies(at: '*');
3})

配置可信主机

默认情况下,Laravel 会响应所有收到的请求,无论 HTTP 请求标头的内容如何Host。此外,Host在 Web 请求期间,标头的值将用于生成应用程序的绝对 URL。

通常,你应该配置你的 Web 服务器(例如 Nginx 或 Apache),使其仅向应用程序发送与指定主机名匹配的请求。但是,如果你无法直接自定义 Web 服务器,并且需要指示 Laravel 仅响应某些主机名,则可以通过Illuminate\Http\Middleware\TrustHosts为应用程序启用中间件来实现。

要启用中间件,您需要在应用程序文件中TrustHosts调用middleware 方法。使用此方法的参数,您可以指定应用程序需要响应的主机名。带有其他标头的传入请求将被拒绝:trustHostsbootstrap/app.phpatHost

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustHosts(at: ['laravel.test']);
3})

默认情况下,来自应用程序 URL 子域的请求也会被自动信任。如果您想禁用此行为,可以使用以下subdomains参数:

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustHosts(at: ['laravel.test'], subdomains: false);
3})

如果您需要访问应用程序的配置文件或数据库来确定受信任的主机,则可以为该at参数提供一个闭包:

1->withMiddleware(function (Middleware $middleware) {
2 $middleware->trustHosts(at: fn () => config('app.trusted_hosts'));
3})