Любите загадки? Событие еще доступно на сайте.
Поделитесь своим кодом и идеями!
Поделитесь своим кодом и идеями!

HTTP-ответы

Создание ответов

Строки и массивы

Все маршруты и контроллеры должны возвращать ответ, который будет отправлен обратно в браузер пользователя. Laravel предлагает несколько разных способов вернуть ответы. Самый простой ответ – это возврат строки из маршрута или контроллера. Фреймворк автоматически преобразует строку в полный HTTP-ответ:

Route::get('/', function () {
    return 'Hello World';
});

Помимо возврата строк из ваших маршрутов и контроллеров, вы также можете возвращать массивы. Фреймворк автоматически преобразует массив в ответ JSON:

Route::get('/', function () {
    return [1, 2, 3];
});

Знаете ли вы, что можете возвращать коллекции Eloquent из ваших маршрутов или контроллеров? Они будут автоматически преобразованы в JSON.

Объекты ответа

Как правило, вы не просто будете возвращать строки или массивы из действий маршрута. Вместо этого вы вернете полные экземпляры Illuminate\Http\Response или шаблоны.

Возврат полного экземпляра Response позволяет вам настроить код состояния и заголовки HTTP ответа. Экземпляр Response наследуется от класса Symfony\Component\HttpFoundation\Response, который содержит множество методов для построения ответов HTTP:

Route::get('/home', function () {
    return response('Hello World', 200)
                  ->header('Content-Type', 'text/plain');
});

Модели и коллекции Eloquent

По желанию можно вернуть модели и коллекции Eloquent ORM прямо из ваших маршрутов и контроллеров. Когда вы это сделаете, Laravel автоматически преобразует модели и коллекции в ответы JSON, учитывая скрытие атрибутов модели:

use App\Models\User;

Route::get('/user/{user}', function (User $user) {
    return $user;
});

Добавление заголовков к ответам

Имейте в виду, что большинство методов ответа можно объединять в цепочку вызовов для гибкого создания экземпляров ответа. Например, вы можете использовать метод header для добавления серии заголовков к ответу перед его отправкой обратно пользователю:

return response($content)
            ->header('Content-Type', $type)
            ->header('X-Header-One', 'Header Value')
            ->header('X-Header-Two', 'Header Value');

Или вы можете использовать метод withHeaders, чтобы указать массив заголовков, которые будут добавлены к ответу:

return response($content)
            ->withHeaders([
                'Content-Type' => $type,
                'X-Header-One' => 'Header Value',
                'X-Header-Two' => 'Header Value',
            ]);

Посредник управления кешем

Laravel содержит посредник cache.headers, используемый для быстрой установки заголовка Cache-Control для группы маршрутов. Директивы должны быть предоставлены с использованием эквивалента “snake case” соответствующей директивы управления кешем и должны быть разделены точкой с запятой. Если в списке директив указан etag, то MD5-хеш содержимого ответа будет автоматически установлен как идентификатор ETag:

Route::middleware('cache.headers:public;max_age=2628000;etag')->group(function () {
    Route::get('/privacy', function () {
        // ...
    });

    Route::get('/terms', function () {
        // ...
    });
});

Добавление файлов Cookies к ответам

Вы можете добавить Cookies к исходящему экземпляру Illuminate\Http\Response, используя метод cookie. Вы должны передать этому методу имя, значение и количество минут, в течение которых куки должен считаться действительным:

return response('Hello World')->cookie(
    'name', 'value', $minutes
);

Метод cookie также принимает еще несколько аргументов, которые используются реже. Как правило, эти аргументы имеют то же назначение и значение, что и аргументы, передаваемые встроенному в PHP методу setcookie method:

return response('Hello World')->cookie(
    'name', 'value', $minutes, $path, $domain, $secure, $httpOnly
);

Если вы хотите, чтобы куки отправлялся вместе с исходящим ответом, но у вас еще нет экземпляра этого ответа, вы можете использовать фасад Cookie, чтобы «поставить в очередь» файлы Cookies для добавления их к ответу при его отправке. Метод queue принимает аргументы, необходимые для создания экземпляра Cookie. Эти файлы Cookies будут добавлены к исходящему ответу перед его отправкой в браузер:

use Illuminate\Support\Facades\Cookie;

Cookie::queue('name', 'value', $minutes);

Если вы хотите сгенерировать экземпляр Symfony\Component\HttpFoundation\Cookie, который может быть добавлен к экземпляру ответа позже, вы можете использовать глобальный помощник cookie. Этот файл Cookies не будет отправлен обратно клиенту, если он не прикреплен к экземпляру ответа:

$cookie = cookie('name', 'value', $minutes);

return response('Hello World')->cookie($cookie);

Досрочное окончание срока действия файлов Cookies

Вы можете удалить куки, обнулив срок его действия с помощью метода withoutCookie исходящего ответа:

return response('Hello World')->withoutCookie('name');

Если у вас еще нет экземпляра исходящего ответа, вы можете использовать метод expire фасада Cookie для обнуления срока действия кук:

Cookie::expire('name');

Файлы Cookies и шифрование

По умолчанию, благодаря middleware Illuminate\Cookie\Middleware\EncryptCookies все файлы Cookies, генерируемые Laravel, зашифрованы и подписаны, поэтому клиент не может их изменить или прочитать. Если вы хотите отключить шифрование для подмножества куки, созданных вашим приложением, вы можете использовать метод encryptCookies в файле bootstrap/app.php вашего приложения:

->withMiddleware(function (Middleware $middleware) {
    $middleware->encryptCookies(except: [
        'cookie_name',
    ]);
})

Перенаправления

Ответы с перенаправлением являются экземплярами класса Illuminate\Http\RedirectResponse и содержат корректные заголовки, необходимые для перенаправления пользователя на другой URL. Есть несколько способов сгенерировать экземпляр RedirectResponse. Самый простой способ – использовать глобальный помощник redirect:

Route::get('/dashboard', function () {
    return redirect('/home/dashboard');
});

По желанию можно перенаправить пользователя в его предыдущее местоположение, например, когда отправленная форма является недействительной. Вы можете сделать это с помощью глобального помощника back. Поскольку эта функция использует сессии, убедитесь, что маршрут, вызывающий функцию back, использует группу посредников web:

Route::post('/user/profile', function () {
    // Валидация запроса ...

    return back()->withInput();
});

Перенаправление на именованные маршруты

Когда вы вызываете помощник redirect без параметров, возвращается экземпляр Illuminate\Routing\Redirector, что позволяет вам вызывать любой метод экземпляра Redirector. Например, чтобы сгенерировать RedirectResponse на именованный маршрут, вы можете использовать метод route:

return redirect()->route('login');

Если ваш маршрут имеет параметры, вы можете передать их в качестве второго аргумента методу route:

// Для маршрута со следующим URI: /profile/{id}

return redirect()->route('profile', ['id' => 1]);

Заполнение параметров с моделей Eloquent

Если вы перенаправляете на маршрут с параметром ID, который извлекается из модели Eloquent, то вы можете просто передать саму модель. ID будет извлечен автоматически:

// Для маршрута со следующим URI: /profile/{id}

return redirect()->route('profile', [$user]);

Если вы хотите настроить значение, которое соответствует параметру маршрута, то вы можете указать столбец при определении параметра маршрута (/profile/{id:slug}) или переопределить метод getRouteKey в вашей модели Eloquent:

/**
 * Получить значение ключа маршрута модели.
 */
public function getRouteKey(): mixed
{
    return $this->slug;
}

Перенаправление к действиям контроллера

Вы также можете генерировать перенаправления на действия контроллера. Для этого передайте имя контроллера и действия методу action:

use App\Http\Controllers\UserController;

return redirect()->action([UserController::class, 'index']);

Если ваш маршрут контроллера требует параметров, вы можете передать их в качестве второго аргумента методу action:

return redirect()->action(
    [UserController::class, 'profile'], ['id' => 1]
);

Перенаправление на внешние домены

Иногда может потребоваться перенаправление на домен за пределами вашего приложения. Вы можете сделать это, вызвав метод away, который создает RedirectResponse без какой-либо дополнительной кодировки URL, валидации или проверки:

return redirect()->away('https://www.google.com');

Перенаправление с кратковременным сохранением данных в сессии

Перенаправление на новый URL-адрес и краткосрочная запись данных в сессию обычно выполняются одновременно. Обычно это делается после успешного выполнения действия, когда вы отправляете сообщение об успешном завершении в сессию. Для удобства вы можете создать экземпляр RedirectResponse и передать данные в сессию в единой текучей цепочке методов:

Route::post('/user/profile', function () {
    // ...

    return redirect('/dashboard')->with('status', 'Profile updated!');
});

После перенаправления пользователя, вы можете отобразить сохраненное из сессии сообщение. Например, используя синтаксис Blade:

@if (session('status'))
    <div class="alert alert-success">
        {{ session('status') }}
    </div>
@endif

Перенаправление с кратковременным сохранением входных данных

Вы можете использовать метод withInput экземпляра RedirectResponse, для передачи входных данных текущего запроса в сессию перед перенаправлением пользователя в новое место. Обычно это делается, если пользователь спровоцировал ошибку валидации. После того как входные данные были переданы в сессию, вы можете легко получить их во время следующего запроса для повторного автозаполнения формы:

return back()->withInput();

Другие типы ответов

Помощник response используется для генерации других типов экземпляров ответа. Когда помощник response вызывается без аргументов, возвращается реализация контракта Illuminate\Contracts\Routing\ResponseFactory. Этот контракт содержит несколько полезных методов для генерации ответов.

Ответы с HTML-шаблонами

Если вам нужен контроль над статусом и заголовками ответа, но также необходимо вернуть HTML-шаблон в качестве содержимого ответа, то вы должны использовать метод view:

return response()
            ->view('hello', $data, 200)
            ->header('Content-Type', $type);

Конечно, вы можете использовать глобальный помощник view, даже если вам не нужно передавать собственные код состояния или заголовки HTTP.

Ответы JSON

Метод json автоматически установит заголовок Content-Type в application/json, а также преобразует переданный массив в JSON с помощью функции json_encode PHP:

return response()->json([
    'name' => 'Abigail',
    'state' => 'CA',
]);

Если вы хотите создать ответ JSONP, вы можете использовать метод json в сочетании с методом withCallback:

return response()
            ->json(['name' => 'Abigail', 'state' => 'CA'])
            ->withCallback($request->input('callback'));

Ответы для загрузки файлов

Метод download используется для генерации ответа, который заставляет браузер пользователя загружать файл по указанному пути. Метод download принимает имя файла в качестве второго аргумента метода, определяющий имя файла, которое видит пользователь, загружающий файл. Наконец, вы можете передать массив заголовков HTTP в качестве третьего аргумента метода:

return response()->download($pathToFile);

return response()->download($pathToFile, $name, $headers);

Symfony HttpFoundation, управляющий загрузкой файлов, требует, чтобы имя загружаемого файла было в кодировке ASCII.

Ответы на файлы

Метод file может использоваться для отображения файла, например изображения или PDF-файла, непосредственно в браузере пользователя вместо запуска загрузки. Этот метод принимает абсолютный путь к файлу в качестве первого аргумента и массив заголовков в качестве второго аргумента:

return response()->file($pathToFile);

return response()->file($pathToFile, $headers);

Потоковые ответы

Передавая данные клиенту по мере их создания, вы можете значительно сократить использование памяти и повысить производительность, особенно для очень больших ответов. Потоковые ответы позволяют клиенту начать обработку данных до того, как сервер завершит их отправку:

function streamedContent(): Generator {
    yield 'Hello, ';
    yield 'World!';
}

Route::get('/stream', function () {
    return response()->stream(function (): void {
        foreach (streamedContent() as $chunk) {
            echo $chunk;
            ob_flush();
            flush();
            sleep(2); // Simulate delay between chunks...
        }
    }, 200, ['X-Accel-Buffering' => 'no']);
});

Внутри Laravel использует функцию буферизации вывода PHP. Как вы можете видеть в приведенном выше примере, вам следует использовать функции ob_flush и flush для отправки буферизованного содержимого клиенту.

Потоковые ответы JSON

Если вам нужно поэтапно передавать данные JSON, вы можете использовать метод streamJson. Этот метод особенно полезен для больших наборов данных, которые необходимо постепенно отправлять в браузер в формате, который можно легко проанализировать с помощью JavaScript:

use App\Models\User;

Route::get('/users.json', function () {
    return response()->streamJson([
        'users' => User::cursor(),
    ]);
});

Потоковые загрузки

По желанию можно превратить строковый ответ переданной функции в загружаемый ответ без необходимости записывать результирующее содержимое на диск. В этом сценарии вы можете использовать метод streamDownload. Этот метод принимает в качестве аргументов замыкание, имя файла и необязательный массив заголовков:

use App\Services\GitHub;

return response()->streamDownload(function () {
    echo GitHub::api('repo')
                ->contents()
                ->readme('laravel', 'laravel')['contents'];
}, 'laravel-readme');

Макрокоманды ответа

Если вы хотите определить собственный ответ, который вы можете повторно использовать в различных маршрутах и контроллерах, то вы можете использовать метод macro фасада Response. Как правило, этот метод следует вызывать в методе boot одного из поставщиков служб вашего приложения, например, App\Providers\AppServiceProvider:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Загрузка любых служб приложения.
     */
    public function boot(): void
    {
        Response::macro('caps', function (string $value) {
            return Response::make(strtoupper($value));
        });
    }
}

Метод macro принимает имя как свой первый аргумент и замыкание – как второй аргумент. Замыкание макрокоманды будет выполнено при вызове имени макрокоманды из реализации ResponseFactory или глобального помощника response:

return response()->caps('foo');