HTTP 请求
Introduction
Laravel 的Illuminate\Http\Request
类提供了一种面向对象的方式来与您的应用程序正在处理的当前 HTTP 请求进行交互,并检索随请求一起提交的输入、cookie 和文件。
与请求交互
访问请求
要通过依赖注入获取当前 HTTP 请求的实例,您应该类型提示Illuminate\Http\Request
在你的路由闭包或控制器方法上类。传入的请求实例将由 Laravel 自动注入服务容器:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Store a new user.
*/
public function store(Request $request): RedirectResponse
{
$name = $request->input('name');
// Store the user...
return redirect('/users');
}
}
如前所述,您还可以键入提示Illuminate\Http\Request
路线关闭班级。服务容器在执行时会自动将传入的请求注入到闭包中:
use Illuminate\Http\Request;
Route::get('/', function (Request $request) {
// ...
});
依赖注入和路由参数
如果您的控制器方法还需要来自路由参数的输入,您应该在其他依赖项之后列出您的路由参数。例如,如果您的路线定义如下:
use App\Http\Controllers\UserController;
Route::put('/user/{id}', [UserController::class, 'update']);
您仍然可以键入提示Illuminate\Http\Request
并访问您的id
通过定义您的控制器方法来路由参数,如下所示:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Update the specified user.
*/
public function update(Request $request, string $id): RedirectResponse
{
// Update the user...
return redirect('/users');
}
}
请求路径、主机和方法
这Illuminate\Http\Request
实例提供了多种方法来检查传入的 HTTP 请求并扩展了Symfony\Component\HttpFoundation\Request
班级。我们将在下面讨论一些最重要的方法。
检索请求路径
这path
方法返回请求的路径信息。因此,如果传入请求的目标是http://example.com/foo/bar
, 这path
方法将返回foo/bar
:
$uri = $request->path();
检查请求路径/路由
这is
方法允许您验证传入的请求路径是否与给定的模式匹配。您可以使用*
使用此方法时将字符作为通配符:
if ($request->is('admin/*')) {
// ...
}
使用routeIs
方法,您可以确定传入请求是否匹配命名路线:
if ($request->routeIs('admin.*')) {
// ...
}
检索请求 URL
要检索传入请求的完整 URL,您可以使用url
或者fullUrl
方法。这url
方法将返回不带查询字符串的 URL,而fullUrl
方法包括查询字符串:
$url = $request->url();
$urlWithQueryString = $request->fullUrl();
如果您想将查询字符串数据附加到当前 URL,您可以调用fullUrlWithQuery
方法。此方法将给定的查询字符串变量数组与当前查询字符串合并:
$request->fullUrlWithQuery(['type' => 'phone']);
检索请求主机
您可以通过以下方式检索传入请求的“主机”host
,httpHost
, 和schemeAndHttpHost
方法:
$request->host();
$request->httpHost();
$request->schemeAndHttpHost();
检索请求方法
这method
方法将返回请求的 HTTP 动词。您可以使用isMethod
验证 HTTP 谓词是否与给定字符串匹配的方法:
$method = $request->method();
if ($request->isMethod('post')) {
// ...
}
请求标头
您可以从Illuminate\Http\Request
实例使用header
方法。如果请求中没有标头,null
将被退回。但是,那header
方法接受可选的第二个参数,如果请求中不存在标头,则将返回该参数:
$value = $request->header('X-Header-Name');
$value = $request->header('X-Header-Name', 'default');
这hasHeader
方法可用于确定请求是否包含给定的标头:
if ($request->hasHeader('X-Header-Name')) {
// ...
}
为了方便起见,bearerToken
方法可用于从Authorization
标头。如果不存在这样的标头,将返回一个空字符串:
$token = $request->bearerToken();
请求 IP 地址
这ip
方法可用于检索向您的应用程序发出请求的客户端的 IP 地址:
$ipAddress = $request->ip();
内容协商
Laravel 提供了几种方法来检查传入请求的请求内容类型,通过Accept
标头。首先,getAcceptableContentTypes
方法将返回一个数组,其中包含请求接受的所有内容类型:
$contentTypes = $request->getAcceptableContentTypes();
这accepts
方法接受内容类型数组并返回true
如果请求接受了任何内容类型。否则,false
将返回:
if ($request->accepts(['text/html', 'application/json'])) {
// ...
}
您可以使用prefers
方法来确定请求最喜欢给定内容类型数组中的哪种内容类型。如果请求不接受任何提供的内容类型,null
将返回:
$preferred = $request->prefers(['text/html', 'application/json']);
由于许多应用程序仅提供 HTML 或 JSON,您可以使用expectsJson
快速确定传入请求是否需要 JSON 响应的方法:
if ($request->expectsJson()) {
// ...
}
PSR-7 请求
这PSR-7标准 指定 HTTP 消息的接口,包括请求和响应。如果您想获取 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) {
// ...
});
Note
如果您从路由或控制器返回 PSR-7 响应实例,它将自动转换回 Laravel 响应实例并由框架显示。
Input
检索输入
检索所有输入数据
您可以检索所有传入请求的输入数据作为array
使用all
方法。无论传入请求是来自 HTML 表单还是 XHR 请求,都可以使用此方法:
$input = $request->all();
使用collect
方法,您可以检索所有传入请求的输入数据作为collection:
$input = $request->collect();
这collect
方法还允许您检索传入请求输入的子集作为集合:
$request->collect('users')->each(function (string $user) {
// ...
});
检索输入值
使用一些简单的方法,您可以访问您的所有用户输入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();
从查询字符串中检索输入
虽然input
方法从整个请求负载(包括查询字符串)中检索值,query
方法只会从查询字符串中检索值:
$name = $request->query('name');
如果请求的查询字符串值数据不存在,将返回此方法的第二个参数:
$name = $request->query('name', 'Helen');
你可以打电话给query
不带任何参数的方法,以便将所有查询字符串值检索为关联数组:
$query = $request->query();
检索 JSON 输入值
当向您的应用程序发送 JSON 请求时,您可以通过input
方法只要Content-Type
请求的标头已正确设置为application/json
.您甚至可以使用“点”语法来检索嵌套在 JSON 数组/对象中的值:
$name = $request->input('user.name');
检索可字符串化的输入值
而不是将请求的输入数据作为原始数据检索string
, 你可以使用string
方法检索请求数据作为实例Illuminate\Support\Stringable
:
$name = $request->string('name')->trim();
检索布尔输入值
在处理诸如复选框之类的 HTML 元素时,您的应用程序可能会收到实际上是字符串的“真实”值。例如,“真”或“开”。为了方便起见,您可以使用boolean
方法将这些值检索为布尔值。这boolean
方法返回true
对于 1,“1”、true、“true”、“on”和“yes”。所有其他值将返回false
:
$archived = $request->boolean('archived');
检索日期输入值
为了方便起见,包含日期/时间的输入值可以使用date
方法。如果请求不包含具有给定名称的输入值,null
将返回:
$birthday = $request->date('birthday');
第二和第三个论据被接受date
方法可用于分别指定日期的格式和时区:
$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
如果输入值存在但格式无效,则InvalidArgumentException
将被抛出;因此,建议您在调用之前验证输入date
方法。
检索枚举输入值
对应于的输入值PHP 枚举 也可以从请求中检索。如果请求不包含具有给定名称的输入值,或者枚举没有与输入值匹配的支持值,null
将被退回。这enum
方法接受输入值的名称和枚举类作为其第一个和第二个参数:
use App\Enums\Status;
$status = $request->enum('status', Status::class);
通过动态属性检索输入
您还可以使用动态属性访问用户输入Illuminate\Http\Request
实例。例如,如果您的申请表之一包含name
字段,您可以像这样访问字段的值:
$name = $request->name;
当使用动态属性时,Laravel 将首先在请求负载中查找参数的值。如果不存在,Laravel 将在匹配的路由参数中搜索该字段。
检索输入数据的一部分
如果您需要检索输入数据的一个子集,您可以使用only
和except
方法。这两种方法都接受一个array
或参数的动态列表:
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
Warning
这only
方法返回您请求的所有键/值对;但是,它不会返回请求中不存在的键/值对。
确定输入是否存在
您可以使用has
确定请求中是否存在值的方法。这has
方法返回true
如果请求中存在该值:
if ($request->has('name')) {
// ...
}
当给定一个数组时,has
方法将确定是否存在所有指定值:
if ($request->has(['name', 'email'])) {
// ...
}
这whenHas
如果请求中存在值,方法将执行给定的闭包:
$request->whenHas('name', function (string $input) {
// ...
});
可以将第二个闭包传递给whenHas
如果请求中不存在指定值,将执行的方法:
$request->whenHas('name', function (string $input) {
// The "name" value is present...
}, function () {
// The "name" value is not present...
});
这hasAny
方法返回true
如果存在任何指定值:
if ($request->hasAny(['name', 'email'])) {
// ...
}
如果你想确定一个值是否出现在请求中并且不是空字符串,你可以使用filled
方法:
if ($request->filled('name')) {
// ...
}
这whenFilled
如果请求中存在值并且不是空字符串,方法将执行给定的闭包:
$request->whenFilled('name', function (string $input) {
// ...
});
可以将第二个闭包传递给whenFilled
如果指定值未“填充”,将执行的方法:
$request->whenFilled('name', function (string $input) {
// The "name" value is filled...
}, function () {
// The "name" value is not filled...
});
要确定请求中是否缺少给定的密钥,您可以使用missing
和whenMissing
方法:
if ($request->missing('name')) {
// ...
}
$request->whenMissing('name', function (array $input) {
// The "name" value is missing...
}, function () {
// The "name" value is present...
});
合并附加输入
有时您可能需要手动将其他输入合并到请求的现有输入数据中。为此,您可以使用merge
方法。如果给定的输入键已经存在于请求中,它将被提供给merge
方法:
$request->merge(['votes' => 0]);
这mergeIfMissing
如果请求的输入数据中不存在相应的键,则可以使用方法将输入合并到请求中:
$request->mergeIfMissing(['votes' => 0]);
旧输入
Laravel 允许您在下一个请求期间保留来自一个请求的输入。此功能对于在检测到验证错误后重新填充表单特别有用。但是,如果您使用的是 Laravel 包含的验证功能,您可能不需要手动直接使用这些会话输入闪烁方法,因为 Laravel 的一些内置验证工具会自动调用它们。
将输入闪烁到会话
这flash
上的方法Illuminate\Http\Request
类会将当前输入闪烁到session 以便在用户对应用程序的下一次请求期间可用:
$request->flash();
您也可以使用flashOnly
和flashExcept
将请求数据的子集闪存到会话的方法。这些方法对于将敏感信息(例如密码)保留在会话之外很有用:
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
闪烁输入然后重定向
由于您经常希望将输入闪烁到会话,然后重定向到上一页,因此您可以轻松地将输入闪烁链接到重定向,使用withInput
方法:
return redirect('form')->withInput();
return redirect()->route('user.create')->withInput();
return redirect('form')->withInput(
$request->except('password')
);
检索旧输入
要从先前的请求中检索闪烁的输入,请调用old
实例上的方法Illuminate\Http\Request
.这old
方法将从中提取先前闪烁的输入数据session:
$username = $request->old('username');
Laravel 还提供了一个全局的old
帮手。如果您在刀片模板, 使用起来更方便old
重新填充表单的助手。如果给定字段不存在旧输入,null
将返回:
<input type="text" name="username" value="{{ old('username') }}">
Cookies
从请求中检索 Cookie
Laravel 框架创建的所有 cookie 都经过加密并使用身份验证代码签名,这意味着如果它们被客户端更改,它们将被视为无效。要从请求中检索 cookie 值,请使用cookie
上的方法Illuminate\Http\Request
实例:
$value = $request->cookie('name');
输入微调和归一化
默认情况下,Laravel 包括App\Http\Middleware\TrimStrings
和Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull
应用程序的全局中间件堆栈中的中间件。这些中间件被列在全局中间件堆栈中App\Http\Kernel
班级。这些中间件将自动修剪请求中的所有传入字符串字段,并将任何空字符串字段转换为null
.这使您不必担心路由和控制器中的这些规范化问题。
禁用输入规范化
如果您想为所有请求禁用此行为,您可以通过从应用程序的中间件堆栈中删除这两个中间件来删除它们$middleware
你的财产App\Http\Kernel
班级。
如果您想为应用程序的一部分请求禁用字符串修剪和空字符串转换,您可以使用skipWhen
两个中间件提供的方法。这个方法接受一个应该返回的闭包true
或者false
指示是否应跳过输入规范化。通常,skipWhen
方法应该在boot
你的应用程序的方法AppServiceProvider
.
use App\Http\Middleware\TrimStrings;
use Illuminate\Http\Request;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
TrimStrings::skipWhen(function (Request $request) {
return $request->is('admin/*');
});
ConvertEmptyStringsToNull::skipWhen(function (Request $request) {
// ...
});
}
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文档 有关这些方法的更多信息。
存储上传的文件
要存储上传的文件,您通常会使用您配置的其中一个filesystems.这UploadedFile
类有一个store
将上传的文件移动到您的其中一个磁盘的方法,该磁盘可能是本地文件系统上的某个位置或 Amazon 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');
Note
有关 Laravel 中文件存储的更多信息,请查看完整的文件存储文档.
配置可信代理
在终止 TLS / SSL 证书的负载均衡器后面运行您的应用程序时,您可能会注意到您的应用程序有时在使用url
帮手。这通常是因为您的应用程序正在从端口 80 上的负载均衡器转发流量,并且不知道它应该生成安全链接。
要解决这个问题,您可以使用App\Http\Middleware\TrustProxies
Laravel 应用程序中包含的中间件,它允许您快速自定义应用程序应信任的负载均衡器或代理。您信任的代理应该作为一个数组列在$proxies
这个中间件的属性。除了配置可信代理外,您还可以配置代理$headers
应该信任:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\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_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;
}
Note
如果您使用的是 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 = '*';
配置可信主机
默认情况下,无论 HTTP 请求的内容如何,Laravel 都会响应它收到的所有请求Host
标头。除此之外Host
在 Web 请求期间为您的应用程序生成绝对 URL 时将使用标头的值。
通常,您应该将 Web 服务器(例如 Nginx 或 Apache)配置为仅向您的应用程序发送与给定主机名匹配的请求。然而,如果你没有能力直接定制你的 web 服务器并且需要指示 Laravel 只响应特定的主机名,你可以通过启用App\Http\Middleware\TrustHosts
您的应用程序的中间件。
这TrustHosts
中间件已经包含在$middleware
您的应用程序堆栈;但是,您应该取消注释以使其变为活动状态。在这个中间件的hosts
方法,您可以指定应用程序应响应的主机名。与其他人的传入请求Host
值标头将被拒绝:
/**
* Get the host patterns that should be trusted.
*
* @return array<int, string>
*/
public function hosts(): array
{
return [
'laravel.test',
$this->allSubdomainsOfApplicationUrl(),
];
}
这allSubdomainsOfApplicationUrl
helper 方法将返回匹配应用程序的所有子域的正则表达式app.url
配置值。在构建使用通配符子域的应用程序时,此帮助程序方法提供了一种允许应用程序的所有子域的便捷方法。