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']);You may still type-hint the Illuminate\Http\Request and access your id route parameter by defining your controller method as follows:
<?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 或 fullUrl 方法。
url 方法将返回不带查询字符串的 URL,而 fullUrl 方法包含查询字符串:
$url = $request->url();
$urlWithQueryString = $request->fullUrl();如果您想向当前 URL 添加查询字符串数据,您可以调用 fullUrlWithQuery 方法。此方法将给定查询字符串变量数组与当前查询字符串合并:
$request->fullUrlWithQuery(['type' => 'phone']);如果您想要获取当前 URL 而不包含指定的查询字符串参数,您可以使用 fullUrlWithoutQuery 方法:
$request->fullUrlWithoutQuery(['type']);你可以通过 host, httpHost, 以及 schemeAndHttpHost 方法来检索传入请求的“host”:
$request->host();
$request->httpHost();
$request->schemeAndHttpHost();该 method 方法将返回请求的 HTTP 动词。您可以使用 isMethod 方法来验证 HTTP 动词是否与给定字符串匹配:
$method = $request->method();
if ($request->isMethod('post')) {
// ...
}您可以使用 header 方法从 Illuminate\Http\Request 实例中获取请求头。如果请求中不存在该请求头,则会返回 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 地址:
$ipAddress = $request->ip();如果您想检索一个IP地址数组,包括所有由代理转发的客户端IP地址,您可以使用ips方法。 “原始”客户端IP地址将位于数组的末尾:
$ipAddresses = $request->ips();通常来说,IP地址应被视为不受信任的、用户控制的输入,并仅用于提供信息。
Laravel provides several methods for inspecting the incoming request's requested content types via the Accept header. First, the getAcceptableContentTypes method will return an array containing all of the content types accepted by the request:
$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 标准 规定了 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 响应实例并由框架显示。
你可以使用 all 方法,将传入请求的所有输入数据作为 array 获取。无论传入请求是来自 HTML 表单还是 XHR 请求,都可以使用此方法:
$input = $request->all();使用 collect 方法, 你可以获取所有传入请求的输入数据作为 集合:
$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 请求时,你可以通过 input 方法访问 JSON 数据,只要请求的 Content-Type 头部已正确设置为 application/json。 你甚至可以使用“点”语法来检索嵌套在 JSON 数组/对象中的值:
$name = $request->input('user.name');不再将请求的输入数据作为原始 string 获取,你可以使用 string 方法将请求数据作为 Illuminate\Support\Stringable 的实例来获取:
$name = $request->string('name')->trim();要以整数形式获取输入值,您可以使用 integer 方法。此方法将尝试把输入值转换为整数。如果输入不存在或转换失败,它将返回您指定的默认值。这对于分页或其他数字输入特别有用:
$perPage = $request->integer('per_page');处理 HTML 元素(例如复选框)时,你的应用程序可能会收到实际上是字符串的“真值”。例如,“true”或“on”。为了方便,你可以使用 boolean 方法将这些值作为布尔值检索。对于 1、“1”、true、“true”、“on”和“yes”,boolean 方法会返回 true。所有其他值都将返回 false:
$archived = $request->boolean('archived');包含数组的输入值可以使用 array 方法获取。此方法总是会将输入值转换为数组。如果请求不包含具有给定名称的输入值,则会返回一个空数组:
$versions = $request->array('versions');为了方便,包含日期/时间 的输入值可以使用 date 方法作为 Carbon 实例检索。如果请求不包含具有给定名称的输入值,则会返回 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);您还可以提供一个默认值,如果该值缺失或无效,该默认值将被返回:
$status = $request->enum('status', Status::class, Status::Pending);如果输入值是一个对应于 PHP 枚举的值数组,你可以使用 enums 方法将该值数组作为枚举实例检索出来:
use App\Enums\Product;
$products = $request->enums('products', Product::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'])) {
// ...
}该 hasAny 方法返回 true,如果存在任何指定值:
if ($request->hasAny(['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...
});如果你想判断请求中是否存在某个值且不为空字符串,你可以使用 filled 方法:
if ($request->filled('name')) {
// ...
}如果您想确定请求中是否缺少某个值或该值是否为空字符串,您可以使用 isNotFilled 方法:
if ($request->isNotFilled('name')) {
// ...
}给定一个数组时,isNotFilled 方法将判断所有指定值是否缺失或为空:
if ($request->isNotFilled(['name', 'email'])) {
// ...
}该 anyFilled 方法返回 true,如果任何指定值不为空字符串:
if ($request->anyFilled(['name', 'email'])) {
// ...
}whenFilled 方法如果请求中存在某个值且该值不是空字符串,则会执行给定的闭包:
$request->whenFilled('name', function (string $input) {
// ...
});第二个闭包可以传递给 whenFilled 方法,该闭包将在指定值不是“filled”时执行:
$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 () {
// 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 的一些内置验证机制会自动调用它们。
Illuminate/Http/Request 类上的 flash 方法会将当前输入闪存到 会话 中,以便它在用户下一次请求应用时可用:
$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')
);要从之前的请求中检索闪存输入,请在一个 Illuminate\Http\Request 实例上调用 old 方法。old 方法将从 会话 中拉取之前闪存的输入数据:
$username = $request->old('username');Laravel 也提供了一个全局的 old 辅助函数。如果你正在 Blade 模板 中显示旧输入,使用 old 辅助函数来重新填充表单会更方便。如果给定字段没有旧输入,将返回 null:
<input type="text" name="username" value="{{ old('username') }}">Laravel 框架创建的所有 cookie 都经过加密并使用认证码签名,这意味着如果客户端更改了它们,它们将被视为无效。要从请求中检索 cookie 值,请在 Illuminate\Http\Request 实例上使用 cookie 方法:
$value = $request->cookie('name');默认情况下,Laravel 在你的应用的全局中间件栈中包含了 Illuminate\Foundation\Http\Middleware\TrimStrings 和 Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull 中间件。这些中间件将自动清除请求中所有传入的字符串字段的空格,以及将所有空字符串字段转换为 null。这让你无需担心在你的路由和控制器中处理这些规范化问题。
如果您想为所有请求禁用此行为,您可以从应用程序的中间件堆栈中移除这两个中间件,方法是在您应用程序的 bootstrap/app.php 文件中调用 $middleware->remove 方法:
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\TrimStrings;
->withMiddleware(function (Middleware $middleware): void {
$middleware->remove([
ConvertEmptyStringsToNull::class,
TrimStrings::class,
]);
})如果你希望对你的应用程序的部分请求禁用字符串修剪和空字符串转换,你可以在你的应用程序的 bootstrap/app.php 文件中使用 trimStrings 和 convertEmptyStringsToNull 中间件方法。这两种方法都接受一个闭包数组,这些闭包应该返回 true 或 false 以指示是否应该跳过输入规范化:
->withMiddleware(function (Middleware $middleware): void {
$middleware->convertEmptyStringsToNull(except: [
fn (Request $request) => $request->is('admin/*'),
]);
$middleware->trimStrings(except: [
fn (Request $request) => $request->is('admin/*'),
]);
})你可以从 Illuminate\Http\Request 实例中检索上传的文件使用 file 方法或动态属性。 file 方法返回一个 Illuminate\Http\UploadedFile 类的实例,该类继承了 PHP SplFileInfo 类并提供了多种用于与文件交互的方法:
$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 方法,它会将上传的文件移动到您的某个磁盘,这可能位于您的本地文件系统上或像 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 助手时有时不会生成 HTTPS 链接。通常这是因为您的应用程序正在从负载均衡器接收端口 80 上的流量,并且不知道它应该生成安全链接。
解决此问题,你可以启用 Illuminate\Http\Middleware\TrustProxies 中间件,该中间件包含在你的 Laravel 应用中,它允许你快速自定义应用程序应信任的负载均衡器或代理。你应使用 trustProxies 中间件方法指定你信任的代理,该方法位于你的应用程序的 bootstrap/app.php 文件中:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(at: [
'192.168.1.1',
'10.0.0.0/8',
]);
})除了配置受信任的代理,您还可以配置应受信任的代理头:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(headers: Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB
);
})[!NOTE]
如果您正在使用 AWS Elastic Load Balancing,headers值应该为Request::HEADER_X_FORWARDED_AWS_ELB。如果您的负载均衡器使用来自 RFC 7239 的标准Forwarded头部,headers值应该为Request::HEADER_FORWARDED。有关可在headers值中使用的常量,请查阅 Symfony 关于 信任代理 的文档。
如果你正在使用 Amazon AWS 或其他“云”负载均衡器提供商,你可能不知道你的实际均衡器的 IP 地址。在这种情况下,你可以使用 * 来信任所有代理:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustProxies(at: '*');
})默认情况下,Laravel 会响应其收到的所有请求,而不管 HTTP 请求的 Host 头的内容。此外,Host 头的值在 Web 请求期间将被用于生成指向你应用程序的绝对 URL。
通常情况下,你应该配置你的 Web 服务器,例如 Nginx 或 Apache,使其只向你的应用程序发送匹配指定主机名的请求。然而,如果你无法直接自定义你的 Web 服务器,并且需要指示 Laravel 只响应某些主机名,你可以通过为你的应用程序启用 Illuminate\Http\Middleware\TrustHosts 中间件来实现这一点。
要启用 TrustHosts 中间件,你应该调用你的应用程序的 bootstrap/app.php 文件中的 trustHosts 中间件方法。使用此方法的 at 参数,你可以指定你的应用程序应该响应的主机名。带有其他 Host 头的传入请求将被拒绝:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustHosts(at: ['laravel.test']);
})默认情况下,来自应用程序 URL 子域的请求也会自动受信任。如果您想禁用此行为,您可以使用 subdomains 参数:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustHosts(at: ['laravel.test'], subdomains: false);
})如果你需要访问你的应用的配置文件或数据库以确定你的受信任主机,你可以提供一个闭包给 at 参数:
->withMiddleware(function (Middleware $middleware): void {
$middleware->trustHosts(at: fn () => config('app.trusted_hosts'));
})