Маршруты: связь URL и кода

Маршрут — это правило, которое говорит Laravel: «когда придёт запрос на этот адрес, выполни вот этот код».

Суть: в файле routes/web.php вы связываете URL и HTTP-метод с обработчиком — замыканием или методом контроллера. Это «карта» вашего приложения.

Когда браузер запрашивает страницу, Laravel должен понять, какой код её обслуживает. За это отвечают маршруты. По сути это таблица соответствий: «адрес /products при методе GET — покажи список товаров». Все веб-маршруты живут в файле routes/web.php, и именно с него начинается любое приложение.

Маршруты задаются через статический класс Route. Самый частый метод — Route::get() для отображения страниц. Есть и другие: post для отправки форм, put/patch для обновления, delete для удаления. Эти методы соответствуют HTTP-глаголам и формируют основу REST-подхода.

Базовый синтаксис

<?php
use Illuminate\Support\Facades\Route;

// Простой маршрут с замыканием
Route::get('/', function () {
    return 'Привет, Laravel!';
});

// Маршрут, возвращающий шаблон
Route::get('/about', function () {
    return view('about');
});

// Маршрут с параметром
Route::get('/products/{id}', function (int $id) {
    return 'Товар номер '.$id;
});

Фигурные скобки {id} — это параметр маршрута: его значение из URL автоматически попадёт в аргумент функции. Запрос /products/42 вернёт «Товар номер 42».

Как работает под капотом

При старте Laravel читает все маршруты и строит из них таблицу. Когда приходит запрос, роутер перебирает маршруты сверху вниз и берёт первый совпавший по адресу и методу. Если совпадения нет — отдаёт ошибку 404.

  Запрос: GET /products/42
      |
      v
  Роутер сверяет с таблицей:
  +------------------------------+
  | GET  /            -> главная |
  | GET  /about       -> about   |
  | GET  /products/{id} <== СОВПАЛО, id=42
  | POST /products    -> store   |
  +------------------------------+
      |
      v
  Запуск обработчика с id=42

Важно понимать, что метод тоже учитывается: GET /products и POST /products — это два разных маршрута с разными обработчиками. Смоделируем работу роутера на Python с учётом метода и параметров.

Попробуй сам ▶

# Роутер, учитывающий метод и параметр {id}
routes = [
    ('GET',  '/',            lambda **k: 'Главная'),
    ('GET',  '/products',    lambda **k: 'Список товаров'),
    ('GET',  '/products/id', lambda id=None: f'Товар {id}'),
    ('POST', '/products',    lambda **k: 'Товар создан'),
]

def dispatch(method, url):
    parts = url.strip('/').split('/')
    for m, pattern, handler in routes:
        pp = pattern.strip('/').split('/')
        if m == method and len(pp) == len(parts):
            params, ok = {}, True
            for a, b in zip(pp, parts):
                if a == 'id':   params['id'] = b
                elif a != b:    ok = False
            if ok:
                return handler(**params)
    return '404'

print(dispatch('GET',  '/products/42'))
print(dispatch('POST', '/products'))
print(dispatch('GET',  '/unknown'))

Частые ошибки

  • Неверный порядок маршрутов. Если общий маршрут /products/{id} стоит выше конкретного /products/new, второй никогда не сработает — первый перехватит.
  • Путать GET и POST. Форма отправляет POST, а маршрут описан как GET — будет ошибка 405 (метод не разрешён).
  • Логика в замыканиях. Замыкания удобны для простых страниц, но для реальной логики используйте контроллеры.

Best practices

  • Для всего, кроме простейших страниц, направляйте маршрут в контроллер, а не в замыкание.
  • Давайте маршрутам имена через ->name() — это упростит генерацию ссылок.
  • Запускайте php artisan route:list, чтобы увидеть все маршруты приложения.

Маршруты редко существуют поодиночке: их удобно группировать. Метод Route::prefix('admin')->group(...) добавляет общий префикс URL ко всем вложенным маршрутам, а Route::middleware('auth')->group(...) навешивает на них общий фильтр. Это убирает повторения и делает карту маршрутов читаемой. Отдельно полезны именованные маршруты: вызов ->name('products.show') даёт маршруту имя, по которому потом генерируют ссылки через хелпер route('products.show', $id). Преимущество в том, что если адрес страницы изменится, достаточно поправить его в одном месте — все ссылки, построенные по имени, обновятся автоматически. Также маршруты поддерживают ограничения параметров через ->where('id', '[0-9]+'), что заставляет роутер принимать, например, только числовые идентификаторы и отбрасывать мусорные URL ещё до контроллера.

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

Проверьте себя
1. Что обозначают фигурные скобки в маршруте /products/{id}?
AКомментарий
BПараметр маршрута, значение которого берётся из URL
CОбязательную форму
DИмя контроллера
2. По какому правилу роутер выбирает обработчик?
AБерёт последний подходящий маршрут
BБерёт первый совпавший по адресу и методу
CВыбирает случайный
DБерёт самый длинный URL