HTTP 请求
简介
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
{
/**
* 存储新用户。
*/
public function store(Request $request): RedirectResponse
{
$name = $request->input('name');
// 存储用户...
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
{
/**
* 更新指定用户。
*/
public function update(Request $request, string $id): RedirectResponse
{
// 更新用户...
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']);如果您想获取不带给定查询字符串参数的当前 URL,可以使用 fullUrlWithoutQuery 方法:
$request->fullUrlWithoutQuery(['type']);检索请求主机
您可以通过 host、httpHost 和 schemeAndHttpHost 方法检索传入请求的"主机":
$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 方法可用于检索向您的应用程序发出请求的客户端的 IP 地址:
$ipAddress = $request->ip();如果您想检索 IP 地址数组,包括代理转发的所有客户端 IP 地址,可以使用 ips 方法。"原始"客户端 IP 地址将位于数组末尾:
$ipAddresses = $request->ips();通常,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()) {
// ...
}如果您需要确定请求是否特别偏好 Markdown 或接受 Markdown 以及其他内容类型,例如在为 AI 代理或其他使用 Markdown 响应的客户端提供服务时,可以使用 wantsMarkdown 和 acceptsMarkdown 方法:
if ($request->wantsMarkdown()) {
// 客户端最偏好的内容类型是 text/markdown...
}
if ($request->acceptsMarkdown()) {
// 客户端接受 Markdown 响应...
}PSR-7 请求
PSR-7 标准为 HTTP 消息(包括请求和响应)指定了接口。如果您想获取 PSR-7 请求的实例而不是 Laravel 请求,您首先需要安装几个库。Laravel 使用 Symfony HTTP Message Bridge 组件将典型的 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 输入值
向应用程序发送 JSON 请求时,只要请求的 Content-Type 头正确设置为 application/json,就可以通过 input 方法访问 JSON 数据。您甚至可以使用"点"语法检索嵌套在 JSON 数组/对象中的值:
$name = $request->input('user.name');检索 Stringable 输入值
您可以不将请求的输入数据作为原始 string 检索,而是使用 string 方法将请求数据作为 Illuminate\Support\Stringable 实例检索:
$name = $request->string('name')->trim();检索整数输入值
要将输入值检索为整数,可以使用 integer 方法。此方法将尝试将输入值转换为整数。如果输入不存在或转换失败,它将返回您指定的默认值。这对于分页或其他数字输入特别有用:
$perPage = $request->integer('per_page');检索布尔输入值
处理像复选框这样的 HTML 元素时,您的应用程序可能会接收到实际上是字符串的"真"值。例如,"true" 或 "on"。为方便起见,您可以使用 boolean 方法将这些值检索为布尔值。boolean 方法对 1、"1"、true、"true"、"on" 和 "yes" 返回 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) {
// "name" 值存在...
}, function () {
// "name" 值不存在...
});如果您想确定请求中是否存在值且不是空字符串,可以使用 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 方法传递第二个闭包,如果指定值未"填充",将执行该闭包:
$request->whenFilled('name', function (string $input) {
// "name" 值已填充...
}, function () {
// "name" 值未填充...
});要确定给定键是否在请求中缺失,可以使用 missing 和 whenMissing 方法:
if ($request->missing('name')) {
// ...
}
$request->whenMissing('name', function () {
// "name" 值缺失...
}, function () {
// "name" 值存在...
});合并额外输入
有时您可能需要手动将额外输入合并到请求的现有输入数据中。为此,可以使用 merge 方法。如果请求上已存在给定输入键,它将被提供给 merge 方法的数据覆盖:
$request->merge(['votes' => 0]);如果请求的输入数据中尚不存在相应键,可以使用 mergeIfMissing 方法将输入合并到请求中: