Пока мы разбираем тему маршрутизации, давайте обновим обработчик showSnippet
, чтобы он принимал параметр id
из строки запроса пользователя следующим образом:
HTTP Метод | Шаблон | Обработчик | Действие |
ANY | / | home | Отображение домашней страницы |
ANY | /snippet?id=1 | showSnippet | Отображение определенной заметки по её идентификатору |
POST | /snippet/create | createSnippet | Создание новой заметки |
Позже мы воспользуемся параметром id
, чтобы выбрать какую-то заметку из базы данных и показать ее пользователю. А пока что мы просто прочитаем значение из параметра id
и вставим его в плейсхолдер ответа.
Рекомендуем вам супер TELEGRAM канал по Golang где собраны все материалы для качественного изучения языка. Удивите всех своими знаниями на собеседовании! 😎
Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.
Нам потребуется обновить функцию showSnippet
, чтобы она выполняла две вещи:
- Она должна получить значение параметра
id
из URL строки запроса используя методr.URL.Query().Get()
. Метод всегда будет возвращать значение параметра в виде строки или пустую строку""
, если нет совпадающего параметра; - Поскольку значение из параметра
id
является ненадежным вводом данных от пользователя, значение нужно сперва проверить. Значение из параметра id должно содержать положительное целое число. Это можно реализовать если мы попытаемся преобразовать строку из id в целое число с помощью функции strconv.Atoi(), а затем проверим если значение больше нуля.
Это делается следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
package main import ( "fmt" // новый импорт "log" "net/http" "strconv" // новый импорт ) ... // Обработчик для отображения содержимого заметки. func showSnippet(w http.ResponseWriter, r *http.Request) { // Извлекаем значение параметра id из URL и попытаемся // конвертировать строку в integer используя функцию strconv.Atoi(). Если его нельзя // конвертировать в integer, или значение меньше 1, возвращаем ответ // 404 - страница не найдена! id, err := strconv.Atoi(r.URL.Query().Get("id")) if err != nil || id < 1 { http.NotFound(w, r) return } // Используем функцию fmt.Fprintf() для вставки значения из id в строку ответа // и записываем его в http.ResponseWriter. fmt.Fprintf(w, "Отображение выбранной заметки с ID %d...", id) } ... |
Посмотрим, как это работает! Если вы не разобрались, где вставить этот код, то не переживайте. Ниже будет весь код из файла main.go
который мы собрали из всех статей и он актуален на текущей момент — текущей статьи.
Перезапустите приложение и попробуйте перейти на URL http://127.0.0.1:4000/snippet?id=123. Вы должны увидеть следующее содержимое:
Также, можете попробовать посетить некоторые URL, у которых есть недействительные значения для параметра id, или нет этого параметра вообще. К примеру:
- http://127.0.0.1:4000/snippet
- http://127.0.0.1:4000/snippet?id=-1
- http://127.0.0.1:4000/snippet?id=foo
Для всех этих запросов вы должны получить ответ 404 page not found
.
Интерфейс io.Writer в Golang
Если заглянуть в документацию для функции fmt.Fprintf(), вы увидите, что в качестве первого параметра она принимает интерфейс io.Writer…
1 |
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) |
… но мы вместо него передали объект http.ResponseWriter
— и все сработало хорошо.
Мы можем это сделать, потому что тип io.Writer
является интерфейсом, а объект http.ResponseWriter
удовлетворяет интерфейсу, потому что у него есть метод w.Write()
.
Если вы новичок в Go, то урок по изучению интерфейсов поможет лучше понять некоторые аспекты текущей статьи. Достаточно знать, что на практике — везде, где вы видите параметр который имеет тип io.Writer
, то ему можно передать объект http.ResponseWriter
. Все написанное после этого будет отправлено как тело HTTP ответа.
Готовый код веб-приложения на Golang
Ниже предоставляем код веб-приложения на текущий момент. По мере прохождения нашего учебника по созданию сайта на golang в конце статьи мы всегда оставляем готовый код. Данный код будет обновляться уже в следующей статье и у вас всегда должен быть актуальная версия кода.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
package main import ( "fmt" "log" "net/http" "strconv" ) // Обработчик главной странице. func home(w http.ResponseWriter, r *http.Request) { // Проверяется, если текущий путь URL запроса точно совпадает с шаблоном "/". Если нет, вызывается // функция http.NotFound() для возвращения клиенту ошибки 404. // Важно, чтобы мы завершили работу обработчика через return. Если мы забудем про "return", то обработчик // продолжит работу и выведет сообщение "Привет из SnippetBox" как ни в чем не бывало. if r.URL.Path != "/" { http.NotFound(w, r) return } w.Write([]byte("Привет из Snippetbox")) } // Обработчик для отображения содержимого заметки. func showSnippet(w http.ResponseWriter, r *http.Request) { // Извлекаем значение параметра id из URL и попытаемся // конвертировать строку в integer используя функцию strconv.Atoi(). Если его нельзя // конвертировать в integer, или значение меньше 1, возвращаем ответ // 404 - страница не найдена! id, err := strconv.Atoi(r.URL.Query().Get("id")) if err != nil || id < 1 { http.NotFound(w, r) return } // Используем функцию fmt.Fprintf() для вставки значения из id в строку ответа // и записываем его в http.ResponseWriter. fmt.Fprintf(w, "Отображение выбранной заметки с ID %d...", id) } // Обработчик для создания новой заметки. func createSnippet(w http.ResponseWriter, r *http.Request) { // Используем r.Method для проверки, использует ли запрос метод POST или нет. Обратите внимание, // что http.MethodPost является строкой и содержит текст "POST". if r.Method != http.MethodPost { // Используем метод Header().Set() для добавления заголовка 'Allow: POST' в // карту HTTP-заголовков. Первый параметр - название заголовка, а // второй параметр - значение заголовка. w.Header().Set("Allow", http.MethodPost) // Используем функцию http.Error() для отправки кода состояния 405 с соответствующим сообщением. http.Error(w, "Метод запрещен!", 405) // Затем мы завершаем работу функции вызвав "return", чтобы // последующий код не выполнялся. return } w.Write([]byte("Создание новой заметки...")) } func main() { // Регистрируем два новых обработчика и соответствующие URL-шаблоны в // маршрутизаторе servemux mux := http.NewServeMux() mux.HandleFunc("/", home) mux.HandleFunc("/snippet", showSnippet) mux.HandleFunc("/snippet/create", createSnippet) log.Println("Запуск веб-сервера на http://127.0.0.1:4000") err := http.ListenAndServe(":4000", mux) log.Fatal(err) } |
Администрирую данный сайт с целью распространения как можно большего объема обучающего материала для языка программирования Go. В IT с 2008 года, с тех пор изучаю и применяю интересующие меня технологии. Проявляю огромный интерес к машинному обучению и анализу данных.
E-mail: vasile.buldumac@ati.utm.md
Образование
Технический Университет Молдовы (utm.md), Факультет Вычислительной Техники, Информатики и Микроэлектроники
- 2014 — 2018 Universitatea Tehnică a Moldovei, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Universitatea Tehnică a Moldovei, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»