Подписывайтесь на наш Telegram канал и будьте в курсе всех событий.
Поделитесь своим кодом и идеями!
Поделитесь своим кодом и идеями!

HTTP-запросы

Введение

Класс 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 конфигурации вашего приложения. Этот метод обеспечивает удобный способ разрешить все поддомены вашего приложения при создании приложения, с использованием поддоменов, определяемых метасимволами подстановки.