请求
这是一篇协同翻译的文章,你可以点击『我来翻译』按钮来参与翻译。
HTTP Requests
介绍
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
方法检索传入请求的 “host”:
$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();
如果你想检索一个包含所有客户端 IP 地址的数组,包括所有代理转发的 IP 地址,你可以使用 ips
方法。「原始」 客户端 IP 地址将位于数组的末端:
$ipAddresses = $request->ips();
通常,应该将 IP 地址视为不可信的、用户控制的输入,并仅出于信息目的使用。
内容协商
Laravel 提供了几个方法通过请求的 Accept
头来检查进来的请求的请求内容类型。首先,getAcceptableContentTypes
方法将返回一个数组,包含请求头中所有的 Accept :
$contentTypes = $request->getAcceptableContentTypes();
accepts
方法接受一个内容类型的数组,如果数组和请求中的 accept 匹配,返回 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 Message Bridge 组件,将典型的 Laravel 请求和响应转换为兼容 PSR-7 的实现:
composer require symfony/psr-http-message-bridge
composer require nyholm/psr7
安装完这些库后,你可以在路由闭包或控制器方法中通过类型提示 PSR-7 请求接口来获取 PSR-7 请求:
use Psr\Http\Message\ServerRequestInterface;
Route::get('/', function (ServerRequestInterface $request) {
// ...
});
[!注意]
I如果你从路由或控制器返回一个 PSR-7 响应实例,框架会自动将其转换回 Laravel 响应实例并显示。
输入(Input)
获取输入
获取所有输入数据
你可以使用 all
方法以数组形式获取请求的所有输入数据。无论请求是来自 HTML 表单还是 XHR 请求,都可使用此方法:
$input = $request->all();
你也可以使用 collect
方法,以 集合(collection) 的形式获取请求的所有输入数据:
$input = $request->collect();
collect
方法还允许你获取请求输入中的某个子集,并以集合(Collection)的形式返回:
$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');
如果请求中没有该查询字符串值,会返回 query
方法第二个参数的默认值:
$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
方法获取请求数据作为一个 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');
Retrieving Date Input Values
For convenience, input values containing dates / times may be retrieved as Carbon instances using the date
method. If the request does not contain an input value with the given name, null
will be returned:
$birthday = $request->date('birthday');
The second and third arguments accepted by the date
method may be used to specify the date's format and timezone, respectively:
$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
If the input value is present but has an invalid format, an InvalidArgumentException
will be thrown; therefore, it is recommended that you validate the input before invoking the date
method.
Retrieving Enum Input Values
Input values that correspond to PHP enums may also be retrieved from the request. If the request does not contain an input value with the given name or the enum does not have a backing value that matches the input value, null
will be returned. The enum
method accepts the name of the input value and the enum class as its first and second arguments:
use App\Enums\Status;
$status = $request->enum('status', Status::class);
You may also provide a default value that will be returned if the value is missing or invalid:
$status = $request->enum('status', Status::class, Status::Pending);
If the input value is an array of values that correspond to a PHP enum, you may use the enums
method to retrieve the array of values as enum instances:
use App\Enums\Product;
$products = $request->enums('products', Product::class);
Retrieving Input via Dynamic Properties
You may also access user input using dynamic properties on the Illuminate\Http\Request
instance. For example, if one of your application's forms contains a name
field, you may access the value of the field like so:
$name = $request->name;
When using dynamic properties, Laravel will first look for the parameter's value in the request payload. If it is not present, Laravel will search for the field in the matched route's parameters.
Retrieving a Portion of the Input Data
If you need to retrieve a subset of the input data, you may use the only
and except
methods. Both of these methods accept a single array
or a dynamic list of arguments:
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
[!WARNING]
Theonly
method returns all of the key / value pairs that you request; however, it will not return key / value pairs that are not present on the request.
Input Presence
You may use the has
method to determine if a value is present on the request. The has
method returns true
if the value is present on the request:
if ($request->has('name')) {
// ...
}
When given an array, the has
method will determine if all of the specified values are present:
if ($request->has(['name', 'email'])) {
// ...
}
The hasAny
method returns true
if any of the specified values are present:
if ($request->hasAny(['name', 'email'])) {
// ...
}
The whenHas
method will execute the given closure if a value is present on the request:
$request->whenHas('name', function (string $input) {
// ...
});
A second closure may be passed to the whenHas
method that will be executed if the specified value is not present on the request:
$request->whenHas('name', function (string $input) {
// The "name" value is present...
}, function () {
// The "name" value is not present...
});
If you would like to determine if a value is present on the request and is not an empty string, you may use the filled
method:
if ($request->filled('name')) {
// ...
}
If you would like to determine if a value is missing from the request or is an empty string, you may use the isNotFilled
method:
if ($request->isNotFilled('name')) {
// ...
}
When given an array, the isNotFilled
method will determine if all of the specified values are missing or empty:
if ($request->isNotFilled(['name', 'email'])) {
// ...
}
The anyFilled
method returns true
if any of the specified values is not an empty string:
if ($request->anyFilled(['name', 'email'])) {
// ...
}
The whenFilled
method will execute the given closure if a value is present on the request and is not an empty string:
$request->whenFilled('name', function (string $input) {
// ...
});
A second closure may be passed to the whenFilled
method that will be executed if the specified value is not "filled":
$request->whenFilled('name', function (string $input) {
// The "name" value is filled...
}, function () {
// The "name" value is not filled...
});
To determine if a given key is absent from the request, you may use the missing
and whenMissing
methods:
if ($request->missing('name')) {
// ...
}
$request->whenMissing('name', function () {
// The "name" value is missing...
}, function () {
// The "name" value is present...
});
Merging Additional Input
Sometimes you may need to manually merge additional input into the request's existing input data. To accomplish this, you may use the merge
method. If a given input key already exists on the request, it will be overwritten by the data provided to the merge
method:
$request->merge(['votes' => 0]);
The mergeIfMissing
method may be used to merge input into the request if the corresponding keys do not already exist within the request's input data:
$request->mergeIfMissing(['votes' => 0]);
Old Input
Laravel allows you to keep input from one request during the next request. This feature is particularly useful for re-populating forms after detecting validation errors. However, if you are using Laravel's included validation features, it is possible that you will not need to manually use these session input flashing methods directly, as some of Laravel's built-in validation facilities will call them automatically.
Flashing Input to the Session
The flash
method on the Illuminate\Http\Request
class will flash the current input to the session so that it is available during the user's next request to the application:
$request->flash();
You may also use the flashOnly
and flashExcept
methods to flash a subset of the request data to the session. These methods are useful for keeping sensitive information such as passwords out of the session:
$request->flashOnly(['username', 'email']);
$request->flashExcept('password');
Flashing Input Then Redirecting
Since you often will want to flash input to the session and then redirect to the previous page, you may easily chain input flashing onto a redirect using the withInput
method:
return redirect('/form')->withInput();
return redirect()->route('user.create')->withInput();
return redirect('/form')->withInput(
$request->except('password')
);
Retrieving Old Input
To retrieve flashed input from the previous request, invoke the old
method on an instance of Illuminate\Http\Request
. The old
method will pull the previously flashed input data from the session:
$username = $request->old('username');
Laravel also provides a global old
helper. If you are displaying old input within a Blade template, it is more convenient to use the old
helper to repopulate the form. If no old input exists for the given field, null
will be returned:
<input type="text" name="username" value="{{ old('username') }}">
Cookies
Retrieving Cookies From Requests
All cookies created by the Laravel framework are encrypted and signed with an authentication code, meaning they will be considered invalid if they have been changed by the client. To retrieve a cookie value from the request, use the cookie
method on an Illuminate\Http\Request
instance:
$value = $request->cookie('name');
Input Trimming and Normalization
By default, Laravel includes the Illuminate\Foundation\Http\Middleware\TrimStrings
and Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull
middleware in your application's global middleware stack. These middleware will automatically trim all incoming string fields on the request, as well as convert any empty string fields to null
. This allows you to not have to worry about these normalization concerns in your routes and controllers.
Disabling Input Normalization
If you would like to disable this behavior for all requests, you may remove the two middleware from your application's middleware stack by invoking the $middleware->remove
method in your application's bootstrap/app.php
file:
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
use Illuminate\Foundation\Http\Middleware\TrimStrings;
->withMiddleware(function (Middleware $middleware) {
$middleware->remove([
ConvertEmptyStringsToNull::class,
TrimStrings::class,
]);
})
If you would like to disable string trimming and empty string conversion for a subset of requests to your application, you may use the trimStrings
and convertEmptyStringsToNull
middleware methods within your application's bootstrap/app.php
file. Both methods accept an array of closures, which should return true
or false
to indicate whether input normalization should be skipped:
->withMiddleware(function (Middleware $middleware) {
$middleware->convertEmptyStringsToNull(except: [
fn (Request $request) => $request->is('admin/*'),
]);
$middleware->trimStrings(except: [
fn (Request $request) => $request->is('admin/*'),
]);
})
Files
Retrieving Uploaded Files
You may retrieve uploaded files from an Illuminate\Http\Request
instance using the file
method or using dynamic properties. The file
method returns an instance of the Illuminate\Http\UploadedFile
class, which extends the PHP SplFileInfo
class and provides a variety of methods for interacting with the file:
$file = $request->file('photo');
$file = $request->photo;
You may determine if a file is present on the request using the hasFile
method:
if ($request->hasFile('photo')) {
// ...
}
Validating Successful Uploads
In addition to checking if the file is present, you may verify that there were no problems uploading the file via the isValid
method:
if ($request->file('photo')->isValid()) {
// ...
}
File Paths and Extensions
The UploadedFile
class also contains methods for accessing the file's fully-qualified path and its extension. The extension
method will attempt to guess the file's extension based on its contents. This extension may be different from the extension that was supplied by the client:
$path = $request->photo->path();
$extension = $request->photo->extension();
Other File Methods
There are a variety of other methods available on UploadedFile
instances. Check out the API documentation for the class for more information regarding these methods.
Storing Uploaded Files
To store an uploaded file, you will typically use one of your configured filesystems. The UploadedFile
class has a store
method that will move an uploaded file to one of your disks, which may be a location on your local filesystem or a cloud storage location like Amazon S3.
The store
method accepts the path where the file should be stored relative to the filesystem's configured root directory. This path should not contain a filename, since a unique ID will automatically be generated to serve as the filename.
The store
method also accepts an optional second argument for the name of the disk that should be used to store the file. The method will return the path of the file relative to the disk's root:
$path = $request->photo->store('images');
$path = $request->photo->store('images', 's3');
If you do not want a filename to be automatically generated, you may use the storeAs
method, which accepts the path, filename, and disk name as its arguments:
$path = $request->photo->storeAs('images', 'filename.jpg');
$path = $request->photo->storeAs('images', 'filename.jpg', 's3');
[!NOTE]
For more information about file storage in Laravel, check out the complete file storage documentation.
Configuring Trusted Proxies
When running your applications behind a load balancer that terminates TLS / SSL certificates, you may notice your application sometimes does not generate HTTPS links when using the url
helper. Typically this is because your application is being forwarded traffic from your load balancer on port 80 and does not know it should generate secure links.
To solve this, you may enable the Illuminate\Http\Middleware\TrustProxies
middleware that is included in your Laravel application, which allows you to quickly customize the load balancers or proxies that should be trusted by your application. Your trusted proxies should be specified using the trustProxies
middleware method in your application's bootstrap/app.php
file:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(at: [
'192.168.1.1',
'10.0.0.0/8',
]);
})
In addition to configuring the trusted proxies, you may also configure the proxy headers that should be trusted:
->withMiddleware(function (Middleware $middleware) {
$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]
If you are using AWS Elastic Load Balancing, theheaders
value should beRequest::HEADER_X_FORWARDED_AWS_ELB
. If your load balancer uses the standardForwarded
header from RFC 7239, theheaders
value should beRequest::HEADER_FORWARDED
. For more information on the constants that may be used in theheaders
value, check out Symfony's documentation on trusting proxies.
信任所有代理
如果你使用的是 Amazon AWS 或其他「云」负载均衡器提供商,则可能不知道实际负载均衡器的 IP 地址。在这种情况下,你可以使用 *
来信任所有代理:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(at: '*');
})
配置可信任的 Host
默认情况下,Laravel 将响应它接收到的所有请求,而不管 HTTP 请求的 Host
标头的内容是什么。此外,在 web 请求期间生成应用程序的绝对 URL 时,将使用 Host
标头的值。
通常情况下,你应该配置你的 Web 服务器(如 Nginx 或 Apache)仅向匹配给定主机名的应用程序发送请求。然而,如果你没有直接自定义你的 Web 服务器的能力,可以通过为你的应用程序启用 Illuminate\Http\Middleware\TrustHosts
中间件,指示 Laravel 仅响应特定主机名的请求。
为了启用 TrustHosts
中间件,你应该在应用程序 bootstrap/app.php
文件中,调用 trustHosts
中间件方法。通过使用该方法中的 at
参数,你可以指定应用程序应该响应的主机名。具有其他 Host
标头值的传入请求将被拒绝:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustHosts(at: ['laravel.test']);
})
默认情况下,来自应用程序 URL 子域名的请求也会自动被信任。如果你想禁用这种行为,可以使用 subdomains
参数:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustHosts(at: ['laravel.test'], subdomains: false);
})
如果你需要访问应用程序的配置文件或数据库来确定你的可信任的主机,你可以再 at
参数提供一个闭包:
->withMiddleware(function (Middleware $middleware) {
$middleware->trustHosts(at: fn () => config('app.trusted_hosts'));
})
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: