HTTP-запросы
11.x
.
Почему это важно?
- Введение
- Взаимодействие с запросом
- Доступ к запросу
- Path, Host и Method запроса
- Заголовки запроса
- IP-адрес запроса
- Согласование содержимого
- Запросы стандарта PSR-7
- Данные полей ввода
- Получение данных полей ввода
- Наличие требуемых данных
- Объединение дополнительных входных данных
- Данные прошлого запроса
- Файлы Cookies
- Обрезание и нормализация значений полей ввода
- Файлы
- Получение загруженных файлов
- Сохранение загруженных файлов
- Конфигурирование доверенных прокси
- Конфигурирование доверенных хостов
Введение
Класс Illuminate\Http\Request
Laravel предлагает объектно-ориентированный способ взаимодействия с текущим HTTP-запросом, обрабатываемым вашим приложением, а также извлечение входных данных, файлов Cookies и файлов, отправленных вместе с запросом.
Взаимодействие с запросом
Доступ к запросу
Чтобы получить экземпляр текущего HTTP-запроса через внедрение зависимостей, вы должны объявить класс Illuminate\Http\Request
в методе контроллера. Экземпляр входящего запроса будет автоматически внедрен контейнером служб Laravel:
<?php
namespace App\Http\Controllers;
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\Request;
class UserController extends Controller
{
/**
* Обновить конкретного пользователя.
*/
public function update(Request $request, string $id): RedirectResponse
{
// Обновляем пользователя ...
return redirect('/users');
}
}
Path, Host и Method запроса
Экземпляр Illuminate\Http\Request
содержит множество методов для интерпретации входящего HTTP-запроса и расширяет класс Symfony\Component\HttpFoundation\Request
. Ниже мы обсудим несколько наиболее важных методов.
Получение Path запроса
Метод 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) запроса
Вы можете получить “host” входящего запроса с помощью методов 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();
Если вы хотите получить массив 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()) {
// ...
}
Запросы стандарта 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) {
// ...
});
Если вы возвращаете экземпляр response по PSR-7 из маршрута или контроллера, он автоматически преобразуется обратно в экземпляр ответа Laravel и отображается фреймворком.
Данные полей ввода
Получение данных полей ввода
Получение данных всех полей ввода
Вы можете получить все данные входящего запроса в виде массива, используя метод all
. Этот метод можно использовать независимо от того, поступает ли входящий запрос из 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 в ваше приложение, вы можете получить доступ к данным JSON с помощью метода input
, если заголовок запроса Content-Type
корректно установлен как application/json
. Вы даже можете использовать «точечную» нотацию для извлечения значений, вложенных в JSON-массивы или объекты:
$name = $request->input('user.name');
Получение экземпляра Stringable из Input
Вместо получения входных данных запроса в виде примитивной string
вы можете использовать метод string
для получения данных запроса как экземпляра Illuminate\Support\Stringable
:
$name = $request->string('name')->trim();
Получение значений логического типа
При работе с элементами HTML, такими как флажки, ваше приложение может получать «логические» значения, которые на самом деле являются строками. Например, строковые «true» или «on». Для удобства вы можете использовать метод boolean
, чтобы получить эти значения как логические. Метод boolean
возвращает true
для 1
, true
, и строковых «1», «true», «on» и «yes». Все остальные значения вернут false
:
$archived = $request->boolean('archived');
Получение значений Даты
Для удобства входные значения, содержащие дату/время, могут быть получены как экземпляры Carbon с использованием метода date
. Если запрос не содержит входного значения с заданным именем, будет возвращен null
:
$birthday = $request->date('birthday');
Второй и третий аргументы, принятые методом date
, могут использоваться для указания формата даты и часового пояса соответственно:
$elapsed = $request->date('elapsed', '!H:i', 'Europe/Madrid');
Если входное значение присутствует, но имеет недопустимый формат, будет выброшено исключение InvalidArgumentException
, поэтому рекомендуется проверять ввод перед вызовом метода date
.
Retrieving Enum Input Values
Входные значения, соответствующие PHP enums, также могут быть извлечены из запроса. Если запрос не содержит входного значения с заданным именем или enum не имеет значения, соответствующего входному значению из request, будет возвращен null
. Метод enum
принимает имя входного значения из request первым аргументом и класс c перечислениями enums в качестве второго:
use App\Enums\Status;
$status = $request->enum('status', Status::class);
Получение данных через динамические свойства
Вы также можете получить доступ к поступившим от пользователя данным, используя динамические свойства экземпляра Illuminate\Http\Request
. Например, если одна из форм вашего приложения содержит поле name
, то вы можете получить доступ к значению поля следующим образом:
$name = $request->name;
При использовании динамических свойств Laravel сначала будет искать значение параметра в информационной части данных запроса. Если его нет, Laravel будет искать поле в соответствующих параметрах маршрута.
Частичное получение данных полей ввода
Если вам нужно получить подмножество входных данных, вы можете использовать методы only
и except
. Оба метода принимают один массив или динамический список аргументов:
$input = $request->only(['username', 'password']);
$input = $request->only('username', 'password');
$input = $request->except(['credit_card']);
$input = $request->except('credit_card');
Метод
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) {
// Значение "имя" присутствует...
}, function () {
// Значение "имя" отсутствует...
});
Если вы хотите определить, присутствует ли значение в запросе и не является ли оно пустой строкой, вы можете использовать метод filled
:
if ($request->filled('name')) {
// ...
}
Метод anyFilled
возвращает true, если какое-либо из указанных значений не является пустой строкой:
if ($request->anyFilled(['name', 'email'])) {
// ...
}}
Метод whenFilled
выполнит указанное замыкание, если значение присутствует в запросе и не является пустой строкой:
$request->whenFilled('name', function (string $input) {
// ...
});
Второе замыкание может быть передано методу whenFilled
которое будет выполнено, если указанное значение «не заполнено»:
$request->whenFilled('name', function ($input) {
// Значение "имя" заполнено ...
}, function () {
// Значение "имя" не заполнено...
});
Чтобы определить, отсутствует ли конкретный ключ в запросе, вы можете использовать метод missing
или whenMissing
:
if ($request->missing('name')) {
// ...
}
$request->whenMissing('name', function (array $input) {
// Значение "name" пропущено...
}, function () {
// Значение "name" присутствует...
});
Объединение дополнительных входных данных
Иногда вам может потребоваться вручную объединить дополнительные входные данные с существующими входными данными запроса. Для достижения этой цели вы можете использовать метод merge
. Если данный входной ключ уже существует в запросе, он будет перезаписан данными, предоставленными методу merge
:
$request->merge(['votes' => 0]);
Метод mergeIfMissing
может использоваться для объединения ввода с запросом, если соответствующие ключи еще не существуют во входных данных запроса:
$request->mergeIfMissing(['votes' => 0]);
Данные прошлого запроса
Laravel позволяет вам сохранить входные данные из текущего запроса на время выполнения следующего запроса. Эта функция особенно полезна для повторного заполнения форм после обнаружения ошибок валидации. Однако, если вы используете содержащуюся в Laravel валидацию, то, возможно, вам не придется вручную использовать эти методы кратковременного сохранения входных данных в сессии напрямую, так как некоторые встроенные средства валидации Laravel будут вызывать их автоматически.
Кратковременное сохранение входных данных в сессии
Метод flash
класса Illuminate\Http\Request
будет сохранять входные данные в сессии, чтобы они были доступны только во время следующего запроса пользователя к приложению:
$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
извлечет ранее записанные входные данные из сессии:
$username = $request->old('username');
Laravel также содержит глобального помощника old
. Если вы показываете данные из предыдущего запроса в шаблоне Blade, удобнее использовать помощник old
для повторного заполнения формы. Если для поля не были указаны данные в предыдущем запросе, то будет возвращен null
:
<input type="text" name="username" value="{{ old('username') }}">
Файлы Cookies
Получение файлов Cookies из запроса
Все файлы Cookies, созданные фреймворком Laravel, зашифрованы и подписаны кодом аутентификации, что означает, что они будут считаться недействительными, если они были изменены клиентом. Чтобы получить значение cookie из запроса, используйте метод cookie
экземпляра Illuminate\Http\Request
:
$value = $request->cookie('name');
Обрезание и нормализация значений полей ввода
По умолчанию Laravel содержит посредников App\Http\Middleware\TrimStrings
и App\Http\Middleware\ConvertEmptyStringsToNull
в глобальном стеке посредников вашего приложения. Эти посредники перечислены в классе App\Http\Kernel
. Первый из упомянутых посредников будет автоматически обрезать все входящие строковые поля запроса, а второй – конвертировать любые пустые строковые поля в null
. Это позволяет вам не беспокоиться об этих проблемах нормализации в ваших маршрутах и контроллерах.
Отключение нормализации значений полей ввода
Если вы хотите отключить это поведение, вы можете удалить два посредника из стека посредников вашего приложения, удалив их из свойства $middleware
вашего класса App\Http\Kernel
.
Если вы хотите отключить обрезку строк и преобразование пустых строк для подмножества запросов к вашему приложению, вы можете использовать метод skipWhen
, предлагаемый обоими middleware. Этот метод принимает замыкание, которое должно возвращать 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) {
// ...
});
}
Файлы
Получение загруженных файлов
Вы можете получить загруженные файлы из экземпляра Illuminate\Http\Request
, используя метод file
или динамические свойства. Метод file
возвращает экземпляр класса Illuminate\Http\UploadedFile
, который расширяет класс SplFileInfo
PHP и содержит различные методы для взаимодействия с файлом:
$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
принимает путь, по которому файл должен храниться относительно настроенного корневого каталога файловой системы. Этот путь не должен содержать имени файла, поскольку в качестве имени файла будет автоматически создан уникальный идентификатор.
Метод 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');
Для получения дополнительной информации о хранилище файлов в Laravel, ознакомьтесь с полной документацией по файловому хранилищу.
Конфигурирование доверенных прокси
При запуске ваших приложений, использующих балансировщик нагрузки, завершающий сертификаты TLS / SSL, вы можете заметить, что ваше приложение иногда не генерирует ссылки протокола HTTPS при использовании глобального помощника 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
{
/**
* Доверенные прокси этого приложения.
*
* @var string|array
*/
protected $proxies = [
'192.168.1.1',
'192.168.1.2',
];
/**
* Заголовки, используемые для обнаружения прокси.
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_FOR | Request::HEADER_X_FORWARDED_HOST | Request::HEADER_X_FORWARDED_PORT | Request::HEADER_X_FORWARDED_PROTO;
}
Если вы используете AWS Elastic Load Balancing, значение
$headers
должно бытьRequest::HEADER_X_FORWARDED_AWS_ELB
. Для получения дополнительной информации о константах, которые могут использоваться в свойстве$headers
, ознакомьтесь с документацией Symfony о доверенных прокси-серверах.
Доверие ко всем прокси
Если вы используете Amazon AWS или другой поставщик «облачных» балансировщиков нагрузки, то вы можете не знать IP-адреса своих фактических балансировщиков. В этом случае вы можете использовать *
, чтобы доверять всем прокси:
/**
* Доверенные прокси этого приложения.
*
* @var string|array
*/
protected $proxies = '*';
Конфигурирование доверенных хостов
По умолчанию Laravel будет отвечать на все запросы, которые он получает, независимо от содержимого заголовка Host
HTTP-запроса. Кроме того, значение заголовка Host
будет использоваться при генерации абсолютных URL-адресов вашего приложения во время веб-запроса.
Как правило, вам следует настроить свой веб-сервер (Nginx или Apache), так, чтобы он обслуживал запросы, соответствующие только указанному имени хоста. Однако, если у вас нет возможности напрямую настроить свой веб-сервер и вам нужно указать Laravel, чтобы он отвечал только на определенные имена хостов, вы можете сделать это, задействовав посредник App\Http\Middleware\TrustHosts
для вашего приложения.
Посредник TrustHosts
уже содержится в стеке $middleware
вашего приложения; однако вы должны раскомментировать его, чтобы он стал активным. В методе hosts
этого посредника вы можете указать имена хостов, на которые ваше приложение должно отвечать. Входящие запросы с другими значениями заголовка Host
будут отклонены:
/**
* Получить шаблоны доверенных хостов.
*
* @return array<int, string>
*/
public function hosts(): array
{
return [
'laravel.test',
$this->allSubdomainsOfApplicationUrl(),
];
}
Метод allSubdomainsOfApplicationUrl
вернет регулярное выражение, соответствующее всем поддоменам значения app.url
конфигурации вашего приложения. Этот метод обеспечивает удобный способ разрешить все поддомены вашего приложения при создании приложения, с использованием поддоменов, определяемых метасимволами подстановки.