Маршрутизация

Основы маршрутизации

Самые простые маршруты Laravel принимают URI и Closure, обеспечивая очень простой и выразительный метод определения маршрутов:

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

Файлы маршрутов по умолчанию

Все маршруты Laravel определены в файлах, расположенных в каталоге routes. Эти файлы автоматически загружаются фреймворком. Файл routes/web.php определяет маршруты для веб-интерфейса. Эти маршруты относятся к группе посредников web, которая предоставляет такие возможности, как состояние сеанса и защита от CSRF. Маршруты в routes/api.php являются stateless (без состояния) и относятся к группе посредников api.

Для большинства приложений вы начнете с определения маршрутов в файле routes/web.php. Доступ к маршрутам, определенным в routes/web.php, можно получить, введя URL определенного маршрута в браузер. Например, Вы можете получить доступ к следующему маршруту, перейдя по адресу http://your-app.test/user:

Route::get('/user', 'UserController@index');

Маршруты, определенные в файле routes/api.php, вложены в группу маршрутов RouteServiceProvider. Внутри этой группы автоматически применяется префикс URI /api, поэтому нет необходимости вручную указывать его в каждом маршруте в этом файле. Изменить префикс и другие опции группы маршрутов можно, изменив класс RouteServiceProvider.

Доступные методы маршрутизации

Маршрутизатор позволяет регистрировать маршруты для любого типа HTTP запроса:

Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);

Иногда вам может понадобиться зарегистрировать маршрут, который отвечает на несколько типов HTTP-запросов. Это можно сделать, используя метод match. Или даже можно зарегистрировать маршрут, который отвечает на все типы HTTP-запросов, используя метод any:

Route::match(['get', 'post'], '/', function () {
    //
});

Route::any('/', function () {
    //
});

CSRF защита

Любые HTML формы, указывающие на маршруты POST, PUT, PATCH или DELETE, определенные в файле маршрутов web, должны включать поле токена CSRF. В противном случае запрос будет отклонен. Подробнее о защите CSRF Вы можете прочитать в документации по CSRF защите:

<form method="POST" action="/profile">
    @csrf
    ...
</form>

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

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

Route::redirect('/here', '/there');

По умолчанию Route::redirect возвращает код состояния 302. Код статуса можно настроить, используя дополнительный третий параметр:

Route::redirect('/here', '/there', 301);

Вы можете использовать метод Route::permanentRedirect для возврата кода статуса 301:

Route::permanentRedirect('/here', '/there');

Маршруты с представлениями

Если маршрут должен только вернуть представление, вы можете использовать метод Route::view. Как и redirect, этот метод предоставляет простой ярлык, так что Вам не нужно определять полный маршрут или контроллер. Метод view принимает URI в качестве первого аргумента, и имя представления — в качестве второго. Кроме того, вы можете предоставить массив данных для передачи в представление третьим необязательным аргументом:

Route::view('/welcome', 'welcome');

Route::view('/welcome', 'welcome', ['name' => 'Taylor']);

Параметры маршрута

Обязательные параметры

Иногда нужно определить сегменты URI в пределах маршрута. Например, вам может понадобиться определить идентификатор пользователя из URL. Вы можете сделать это, определив параметры маршрута:

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

Вы можете определить столько параметров маршрута, сколько требуется:

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
    //
});

Параметры маршрута всегда заключены в фигурные скобки {}, должны состоять из буквенных знаков, и не могут содержать символ -. Вместо символа - используйте символ подчеркивания (_). Параметры маршрута вставляются в функции обратного вызова/контроллеры маршрута в зависимости от их порядка — имена аргументов функции обратного вызова/контроллера не имеют значения.

Необязательные параметры

Иногда может понадобиться указать параметр маршрута, но сделать его присутствие необязательным. Вы можете сделать это, поставив символ ? после имени параметра. Убедитесь, что соответствующая переменная маршрута имеет значение по умолчанию:

Route::get('user/{name?}', function ($name = null) {
    return $name;
});

Route::get('user/{name?}', function ($name = 'John') {
    return $name;
});

Ограничения регулярными выражениями

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

Route::get('user/{name}', function ($name) {
    //
})->where('name', '[A-Za-z]+');

Route::get('user/{id}', function ($id) {
    //
})->where('id', '[0-9]+');

Route::get('user/{id}/{name}', function ($id, $name) {
    //
})->where(['id' => '[0-9]+', 'name' => '[a-z]+']);

Глобальные ограничения

Если вы хотите, чтобы параметр маршрута всегда был ограничен заданным регулярным выражением, то можете использовать метод pattern. Эти шаблоны следует определять в методе boot вашего RouteServiceProvider:

/**
 * Define your route model bindings, pattern filters, etc.
 *
 * @return void
 */
public function boot()
{
    Route::pattern('id', '[0-9]+');

    parent::boot();
}

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

Route::get('user/{id}', function ($id) {
    // Only executed if {id} is numeric...
});

Использоание прямого слэша

Компонент маршрутизации Laravel позволяет использовать все символы, кроме /. Вы должны явно разрешить / быть частью плейсхолдера, используя регулярное выражение условия where:

Route::get('search/{search}', function ($search) {
    return $search;
})->where('search', '.*');

Использование прямого слэша поддерживаются только в пределах последнего сегмента маршрута.

Именованные маршруты

Именованные маршруты позволяют удобно генерировать URL или перенаправлять для конкретных маршрутов. Вы можете задать имя, вызвав метод name в определении маршрута:

Route::get('user/profile', function () {
    //
})->name('profile');

Также можно указать имена маршрутов для действий контроллера:

Route::get('user/profile', 'UserProfileController@show')->name('profile');

Названия маршрутов всегда должны быть уникальными.

Генерация URL-адресов по имени маршрута

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

// Generating URLs...
$url = route('profile');

// Generating Redirects...
return redirect()->route('profile');

Если именованный маршрут определяет параметры, то можете передать параметры в качестве второго аргумента в функцию route. Данные параметры будут автоматически вставлены в URL в правильном порядке:

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1]);

Если вы передадите в массив дополнительные параметры, то эти пары ключ/значение будут автоматически добавлены в строку запроса сгенерированного URL:

Route::get('user/{id}/profile', function ($id) {
    //
})->name('profile');

$url = route('profile', ['id' => 1, 'photos' => 'yes']);

// /user/1/profile?photos=yes

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

Проверка текущего маршрута

Если вы хотите определить, был ли текущий запрос направлен на заданный именованный маршрут, то можете использовать метод named на экземпляре Route. Например, вы можете проверить текущее название маршрута из посредника маршрута:

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if ($request->route()->named('profile')) {
        //
    }

    return $next($request);
}

Группы маршрутов

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

Вложенные группы пытаются умно "объединить" атрибуты со своей родительской группой. Посредники и условия where объединяются, в то время как имена, пространства имен и префиксы добавляются. Разделители пространств имен и слэши в префиксах URI добавляются при необходимости автоматически.

Посредники

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

Route::middleware(['first', 'second'])->group(function () {
    Route::get('/', function () {
        // Uses first & second Middleware
    });

    Route::get('user/profile', function () {
        // Uses first & second Middleware
    });
});

Пространства имен

Другим распространенным случаем использования групп маршрутов является назначение одного и того же пространства имён PHP группе контроллеров методом namespace:

Route::namespace('Admin')->group(function () {
    // Controllers Within The "App\Http\Controllers\Admin" Namespace
});

Помните, что по умолчанию RouteServiceProvider включает файлы маршрутов в группу пространств имен, позволяя регистрировать маршруты контроллеров без указания полного префикса App\Http\Controllers. Таким образом, вам нужно указать только ту часть пространства имен, которая идет после базового App\Http\Controllers пространства имен.

Маршрутизация поддоменов

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

Route::domain('{account}.myapp.com')->group(function () {
    Route::get('user/{id}', function ($account, $id) {
        //
    });
});

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

Префиксы маршрута

Метод prefix может быть использован для префиксации каждого маршрута в группе с заданным URI. Например, вы можете добавить префикс admin во все URI маршрута внутри группы:

Route::prefix('admin')->group(function () {
    Route::get('users', function () {
        // Matches The "/admin/users" URL
    });
});

Префикс имен маршрутов

Метод name может использоваться для префиксации каждого имени маршрута в группе с заданной строкой. Например, Вы можете добавить префикс admin во все имена сгруппированных маршрутов. Данная строка будет приклеена к названию маршрута в точности так, как она указано, поэтому мы обязательно обеспечим разделительный символ . в префиксе:

Route::name('admin.')->group(function () {
    Route::get('users', function () {
        // Route assigned name "admin.users"...
    })->name('users');
});

Внедрение моделей в маршруты

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

Неявная привязка

Laravel автоматически разрешает Eloquent модели, определенные в маршрутах или действиях контроллера, имена переменных с подсказкой типа которых совпадают с именем участка маршрута. Например:

Route::get('api/users/{user}', function (App\User $user) {
    return $user->email;
});

Так как переменная $user имеет подсказку типа App\User Eloquent модели, а имя переменной совпадает с URI сегментом {user}, Laravel автоматически внедрит экземпляр модели, имеющий ID, совпадающий с соответствующим значением из URI запроса. Если соответствующий экземпляр модели не найден в базе данных, автоматически будет сгенерирован ответ HTTP 404.

Настройка ключа

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

Route::get('api/posts/{post:slug}', function (App\Post $post) {
    return $post;
});

Пользовательские ключи и область видимости

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

use App\Post;
use App\User;

Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

При использовании неявной привязки по пользовательскому ключу в качестве вложенного параметра маршрута, Laravel автоматически выполнит запрос на получение вложенной модели от ее родителя, используя соглашения для угадывания имени отношения на родительском. В этом случае, предполагается, что модель User имеет отношение с именем posts (множественное число имени параметра маршрута), которое может быть использовано для получения модели Post.

Настройка имени ключа по умолчанию

Если Вы хотите, чтобы привязка модели использовала столбец базы данных по умолчанию, отличный от id, при получении заданного класса модели, Вы можете переопределить метод getRouteKeyName на модели Eloquent:

/**
 * Get the route key for the model.
 *
 * @return string
 */
public function getRouteKeyName()
{
    return 'slug';
}

Явная привязка

Для регистрации явной привязки используйте метод model маршрутизатора, чтобы указать класс для данного параметра. Определение явной привязки модели необходимо делать в методе boot класса RouteServiceProvider:

public function boot()
{
    parent::boot();

    Route::model('user', App\User::class);
}

Далее определите маршрут, содержащий параметр {user}:

Route::get('profile/{user}', function (App\User $user) {
    //
});

Так как мы привязали все параметры {user} к модели App\User, в маршрут будет вставлен экземпляр User. Так, например, запрос к profile/1 будет внедрять экземпляр User из базы данных, имеющей ID 1.

Если соответствующий экземпляр модели не найден в базе данных, автоматически будет сгенерирован ответ HTTP 404.

Настройка логики разрешения

Если Вы хотите использовать свою собственную логику разрешения, то используйте метод Route::bind. Функция обратного вызова, которую Вы передаете методу bind, получит значение URI-сегмента и должна вернуть экземпляр класса, который должен быть внедрен в маршрут:

/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    parent::boot();

    Route::bind('user', function ($value) {
        return App\User::where('name', $value)->firstOrFail();
    });
}

В качестве альтернативы, вы можете переопределить метод resolveRouteBinding на модели Eloquent. Этот метод получит значение сегмента URI и должен вернуть экземпляр класса, который должен быть внедрен в маршрут:

/**
 * Retrieve the model for a bound value.
 *
 * @param  mixed  $value
 * @param  string|null  $field
 * @return \Illuminate\Database\Eloquent\Model|null
 */
public function resolveRouteBinding($value, $field = null)
{
    return $this->where('name', $value)->firstOrFail();
}

Запасные маршруты

Используя метод Route::fallback, вы можете определить маршрут, который будет выполняться, когда ни один другой маршрут не будет соответствовать входящему запросу. Обычно, необработанные запросы автоматически выводят страницу "404" через обработчик исключений вашего приложения. Однако, так как вы можете определить маршрут "отката" в файле routes/web.php, все посредники в группе web будут применяться к этому маршруту. Вы можете добавлять дополнительных посредников к этому маршруту по необходимости:

Route::fallback(function () {
    //
});

Запасной маршрут всегда должен быть последним маршрутом, зарегистрированным в вашем приложении.

Ограничение скорости

Laravel включает в себя посредника для ограничения доступа к маршрутам внутри приложения. Для начала, назначьте посредника throttle маршруту или группе маршрутов. Этот посредник принимает два параметра, которые определяют максимальное количество запросов, которые могут быть сделаны в заданное количество минут. Например, укажем, что аутентифицированный пользователь может получить доступ к следующей группе маршрутов 60 раз в минуту:

Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Динамическое ограничение скорости

Вы можете указать динамический максимум запроса, основываясь на атрибуте аутентифицированной модели User. Например, если Ваша User модель содержит атрибут rate_limit, Вы можете передать имя атрибута в посредник throttle, чтобы оно использовалось для вычисления максимального количества запросов:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Различные ограничения для гостевых и аутентифицированных пользователей

Вы можете указать разные ограничения для гостевых и аутентифицированных пользователей. Например, Вы можете указать максимум 10 запросов в минуту для гостей и 60 для аутентифицированных пользователей:

Route::middleware('throttle:10|60,1')->group(function () {
    //
});

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

Route::middleware('auth:api', 'throttle:10|rate_limit,1')->group(function () {
    Route::get('/user', function () {
        //
    });
});

Ограничения для сегментов

Обычно, вы укажете один лимит скорости для всего вашего API. Однако, ваше приложение может потребовать различных лимитов для разных сегментов вашего API. Если это так, то Вам нужно будет передать имя сегмента в качестве третьего аргумента в посредник throttle:

Route::middleware('auth:api')->group(function () {
    Route::middleware('throttle:60,1,default')->group(function () {
        Route::get('/servers', function () {
            //
        });
    });

    Route::middleware('throttle:60,1,deletes')->group(function () {
        Route::delete('/servers/{id}', function () {
            //
        });
    });
});

Подмена метода запроса в формах

HTML формы не поддерживают действия PUT, PATCH или DELETE. Поэтому при определении маршрутов PUT, PATCH или DELETE, которые вызываются из HTML формы, вам нужно будет добавить в форму скрытое поле _method. Значение, отправленное с полем _method, будет использовано в качестве метода HTTP запроса:

<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    <input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>

Вы можете использовать Blade директиву @method для генерации поля _method:

<form action="/foo/bar" method="POST">
    @method('PUT')
    @csrf
</form>

Доступ к текущему маршруту

Вы можете использовать методы current, currentRouteName и currentRouteAction на фасаде Route для доступа к информации о маршруте, по которому обрабатывается входящий запрос:

$route = Route::current();

$name = Route::currentRouteName();

$action = Route::currentRouteAction();

Для просмотра всех доступных методов обратитесь к документации API класса фасада Route, и экземпляра Route.

Cross-Origin Resource Sharing (CORS)

Laravel может автоматически отвечать на запросы CORS OPTIONS значениями, которые вы настраиваете. Все настройки CORS могут быть сконфигурированы в конфигурационном файле cors, а запросы OPTIONS будут автоматически обрабатываться посредником HandleCors, который по умолчанию включен в глобальный стек посредников.

Для получения дополнительной информации о CORS и заголовках CORS обратитесь к документации MDN по CORS.

Last updated