Содержание статьи

Веб-приложение только с одним маршрутом не очень интересное… или не очень полезное! Давайте добавим несколько маршрутов, чтобы наше приложение начало принимать более динамичную форму.

URL-Шаблон Обработчик Действие
/ home Отображает домашнюю страницу
/snippet showSnippet Отображает определенную заметку
/snippet/create createSnippet Создает новую заметку

Откроем файл main.go и обновим его содержимое следующим кодом:

Премиум 👑 канал по Golang

Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎

Подписаться на канал

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК ЧАТ в Telegram

Не забудьте сохранить данные изменения и затем перезапустите веб-приложение:

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

  1. http://127.0.0.1:4000/
  2. http://127.0.0.1:4000/snippet
  3. http://127.0.0.1:4000/snippet/create

Создание сайта на Golang

Многоуровневый роутинг веб-приложения

Теперь, когда два новых маршрута созданы, давайте разберем теорию…

Servemux (маршрутизатор HTTP запросов) в Go поддерживает два разных типа URL-шаблонов: фиксированные пути и многоуровневые пути. Фиксированные пути не заканчиваются косой чертой, тогда как многоуровневые пути заканчиваются косой чертой.

Два наших новых шаблона — "/snippet" и "/snippet/create" — являются примерами фиксированных путей. В servemux такие шаблоны фиксированного пути сопоставляются (и вызывается соответствующий обработчик) только тогда, когда путь URL-запроса точно совпадает с фиксированным путем.

В то время как, роутинг "/" является примером многоуровневого пути (потому что он заканчивается косой чертой). Другим примером является что-то вроде "/static/". Шаблоны путей сопоставляются (вызывается соответствующий обработчик) всякий раз, когда начало пути URL запроса совпадает с путем поддерева.

У многоуровневых путей в конце может быть какой-то вспомогательный символ. К примеру, "/**" или "/static/**".

Теперь понятно, почему шаблон "/" действует по сценарию «catch-all» (ловим все запросы). По сути, данный шаблон
означает совпадение с одним слэшем, за которым следует что-нибудь (или вообще ничего).

Обработка несуществующих URL маршрутов — Ошибка 404

Что, если нам не нужно, чтобы шаблон "/" улавливал абсолютно все запросы?

К примеру, в приложении, которое мы создаем, требуется, чтобы домашняя страница отображалась, если — и только если — URL-путь запроса точно совпадает с маршрутом "/" и за ней ничего больше нет. В противном случае пользователь должен получить ошибку 404 страница не найдена.

Для этой цели, поведение маршрутизатора HTTP запросов servemux в Go изменить невозможно, но вы можете добавить простую if-проверку в функцию обработчик home. Это в конечном итоге даст тот же эффект:

Обновите функцию home из файла main.go, затем перезапустите веб-сервер и откройте несуществующею страницу вроде  http://127.0.0.1:4000/menya-net. Вы должны получить следующий ответ:

Golang обработка ошибки 404

DefaultServeMux

Возможно, при работе с Go вы уже встречали функции http.Handle() и http.HandleFunc(). Они позволяют регистрацию маршрутов без объявления самого servemux, например:

Где-то за кулисами, эти функции регистрируют свои маршруты с помощью так называемого DefaultServeMux. В этом нет ничего особенного — это обычный servemux, который мы уже использовали, но он инициализируется сам по умолчанию и сохраняется в глобальной переменной которая  в свою очередь хранится в модуле net/http. Вот как это выглядит в исходном коде пакета net/http:

Хотя такой подход может значительно уменьшить код (на целую одну строку!!!), мы не рекомендуем использовать DefaultServeMux для ваших приложений.

Поскольку DefaultServeMux является глобальной переменной, любой пакет может получить к ней доступ и зарегистрировать маршрут — включая любые сторонние пакеты, которые использует ваше приложение. Если один из сторонних пакетов скомпрометирован, они могут манипулировать DefaultServeMux, и ваше веб-приложение будет обрабатывать вредоносные HTTP запросы и гипотетически может быть создан backdoor для доступа к файлам на сервере.

В целях безопасности — рекомендуется избегать использование DefaultServeMux и соответствующих вспомогательных функций. Вместо этого лучше используйте свой собственный servemux с локальной областью видимости, как мы делали до сих пор.

Особенности использования servemux

  • В servemux, более длинные проверочные URL-шаблоны всегда обладают приоритетом перед более короткими. Таким образом, если servemux содержит несколько проверочных шаблонов, соответствующих HTTP запросу, он всегда отправит запрос обработчику с более детальным шаблоном проверки URL совпадения. Приятный побочный эффект заключается в том, что вы можете регистрировать шаблоны в любом порядке, и это не меняет поведения servemux;
  • URL-пути запросов автоматически очищаются. Если путь запроса содержит такие символы как . или .. или повторяющиеся слэшы, пользователь будет автоматически перенаправлен на эквивалентный чистый URL. Например, если пользователь делает запрос к /foo/bar/..//baz, он автоматически получит ответ 301 Permanent Redirect и будет перенаправлен на /foo/baz;
  • Если многоуровневый путь был зарегистрирован и HTTP запрос получен для этого пути без слэша в конце, то пользователю автоматически будет перенаправлен через 301 Permanent Redirect на путь с добавленной косой чертой. Например, если вы зарегистрировали многоуровневый путь /foo/, то любой запрос к /foo будет перенаправлен на /foo/.

Добавление домена в роутинг HTTP запросов

Можно включить названия домена в проверочный URL-шаблон. Это может быть полезно, когда требуется напрямую перенаправить все HTTP запросы каноничному URL, или если приложение действует как бэкенд для нескольких сайтов или сервисов на разных языках. В зависимости от суб-домена, меняется и язык сайта. К примеру:

Когда дело доходит до сопоставления с URL-шаблоном, сначала проверяются любые шаблоны где используется имя домена. В случае совпадения, запрос будет отправлен соответствующему обработчику. Только в том случае, если не найдено совпадений для конкретного домена, будут проверены шаблоны, которые не связаны с именем домена.

Что насчет REST маршрутизации?

Важно понимать, что функциональность маршрутизации запросов, предоставляемая от servemux в Go, довольно легкая. Она не поддерживает маршрутизацию на основе метода запроса (вроде разных обработчиков для POST и GET методов на один и тот же URL), динамические URL с переменными в них, а также не поддерживает шаблоны на основе регулярных выражений. Если у вас есть опыт использования таких фреймворков, как Rails, Django или Laravel, это может показаться немного ограничивающим… и неожиданным!

Пусть это вас не смущает. Реальность такова, что servemux в Go все еще может многое реализовать, и для большинства веб-приложений этого вполне достаточно. Если вам нужно больше возможностей, то существует огромный выбор маршрутизаторов на github вроде mux, httprouter или chi, которые можно использовать вместо встроенного servemux от Go. Мы рассмотрим некоторые популярные варианты будущих уроках.

Финальный код на текущий момент