Skip to content

Latest commit

 

History

History
652 lines (424 loc) · 43.3 KB

requests.md

File metadata and controls

652 lines (424 loc) · 43.3 KB

Laravel 9 · 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
{
    /**
     * Сохранить нового пользователя.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }
}

Вы также можете объявить класс 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
{
    /**
     * Обновить конкретного пользователя.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  string  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

Путь, хост и метод запроса

Экземпляр 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']);

Получение хоста запроса

Вы можете получить «хост» входящего запроса с помощью методов 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();

Согласование содержимого

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) {
    //
});

Примечание
Если вы вернете экземпляр ответа PSR-7 из маршрута или контроллера, он будет автоматически преобразован обратно в экземпляр ответа Laravel и отобразится фреймворком.

Данные полей ввода

Получение данных полей ввода

Получение данных всех полей ввода

Вы можете получить все данные входящего запроса в виде массива, используя метод all. Этот метод можно использовать независимо от того, поступает ли входящий запрос из HTML-формы или является запросом XHR:

$input = $request->all();

Используя метод collect, вы можете получить все входные данные входящего запроса в виде коллекции:

$input = $request->collect();

Метод collect также позволяет вам получить подмножество входных данных запроса в виде коллекции:

$request->collect('users')->each(function ($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');

Получение строковых значений входных данных

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

Получение значений перечисляемых типов

Входные значения, соответствующие перечислениям PHP, также могут быть получены из запроса. Если запрос не содержит входного значения с заданным именем или перечисление не имеет резервного значения, соответствующего входному значению, то будет возвращено null. Метод enum принимает имя входного значения и класс перечисления в качестве первого и второго аргументов, соответственно:

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'])) {
    //
}

Метод whenHas выполнит переданное замыкание, если в запросе присутствует значение:

$request->whenHas('name', function ($input) {
    //
});

Второе замыкание, переданное методу whenHas, будет выполнено, если указанное значение отсутствует в запросе:

$request->whenHas('name', function ($input) {
    // Значение `name` присутствует ...
}, function () {
    // Значение `name` отсутствует ...
});

Метод hasAny возвращает true, если присутствует какое-либо из указанных значений:

if ($request->hasAny(['name', 'email'])) {
    //
}

Если вы хотите определить, присутствует ли значение в запросе и не является ли оно пустой строкой, то вы можете использовать метод filled:

if ($request->filled('name')) {
    //
}

Метод whenFilled выполнит указанное замыкание, если значение присутствует в запросе и не является пустой строкой:

$request->whenFilled('name', function ($input) {
    //
});

Второе замыкание, переданное методам whenFilled, будет выполнено, если указанное значение не «заполнено»:

$request->whenFilled('name', function ($input) {
    // Значение `name` заполнено ...
}, function () {
    // Значение `name` не заполнено ...
});

Чтобы определить, отсутствует ли конкретный ключ в запросе, вы можете использовать метод missing или whenMissing:

if ($request->missing('name')) {
    //
}

$request->whenMissing('name', function ($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 и Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull в глобальном стеке посредников вашего приложения. Эти посредники перечислены в классе App\Http\Kernel. Первый из упомянутых посредников будет автоматически обрезать все входящие строковые поля запроса, а второй – конвертировать любые пустые строковые поля в null. Это позволяет вам не беспокоиться об этих проблемах нормализации в ваших маршрутах и контроллерах.

Отключение нормализации ввода

Если вы хотите отключить это поведение для всех запросов, то вы можете удалить два посредника из стека посредников вашего приложения, удалив их из свойства $middleware вашего класса App\Http\Kernel.

Если вы хотите отключить обрезание строк и преобразование пустой строки для подмножества запросов вашего приложения, то вы можете использовать метод skipWhen, предлагаемый обоими посредниками. Этот метод принимает замыкание, которое должно возвращать true или false, чтобы указать, следует ли пропустить нормализацию ввода. Как правило, вызов метода skipWhen осуществляется в методе boot поставщика App\Providers\AppServiceProvider:

use App\Http\Middleware\TrimStrings;
use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;

/**
 * Загрузка любых служб приложения.
 *
 * @return void
 */
public function boot()
{
    TrimStrings::skipWhen(function ($request) {
        return $request->is('admin/*');
    });

    ConvertEmptyStringsToNull::skipWhen(function ($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 доступно множество других методов. Дополнительные сведения об этих методах смотрите в исходниках этого класса.

Сохранение загруженных файлов

Чтобы сохранить загруженный файл, вы обычно будете использовать одно из ваших настроенных файловых хранилищ. Класс 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
 */
public function hosts()
{
    return [
        'laravel.test',
        $this->allSubdomainsOfApplicationUrl(),
    ];
}

Метод allSubdomainsOfApplicationUrl вернет регулярное выражение, соответствующее всем поддоменам значения app.url конфигурации вашего приложения. Этот метод обеспечивает удобный способ разрешить все поддомены вашего приложения при создании приложения, с использованием поддоменов, определяемых метасимволами подстановки.