1. Основы
  2. HTTP Responses

Присоединяйся к нашему Telegram сообществу @webblend!

Здесь ты найдешь сниппеты по Laravel и полезные советы по веб-разработке.

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

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

Все маршруты и контроллеры должны возвращать ответ, который будет отправлен обратно в браузер пользователя. 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 для группы маршрутов. Директивы должны быть предоставлены с использованием "змеиного регистра" эквивалента соответствующей директивы Cache-Control и должны разделяться точкой с запятой. Если в списке директив указан etag, в качестве идентификатора ETag автоматически будет установлен MD5-хеш содержимого ответа:

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

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

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

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

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

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

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

use Illuminate\Support\Facades\Cookie;
 
Cookie::queue('name', 'value', $minutes);

Создание экземпляров cookie

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

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

Преждевременное истечение срока действия cookie

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

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

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

Cookie::expire('name');

Cookie и шифрование

По умолчанию все cookie, созданные Laravel, зашифрованы и подписаны, чтобы их нельзя было изменить или прочитать клиентом. Если вы хотите отключить шифрование для подмножества cookie, созданных вашим приложением, вы можете использовать свойство $except middleware App\Http\Middleware\EncryptCookies, которое находится в каталоге app/Http/Middleware:

/**
* Имена файлов cookie, которые не должны быть зашифрованы.
*
* @var array
*/
protected $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. Этот контракт предоставляет несколько полезных методов для создания ответов.

Ответы представлений

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

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

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

Ответы 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-имя файла.

Загрузки в потоке

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

use App\Services\GitHub;
 
return response()->streamDownload(function () {
echo GitHub::api('repo')
->contents()
->readme('laravel', 'laravel')['contents'];
}, 'laravel-readme.md');

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

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

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

Макросы ответов

Если вы хотите определить пользовательский ответ, который можно использовать в различных ваших маршрутах и контроллерах, вы можете использовать метод 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');