# 4.1 Работа с формами Перед тем, как начать, давайте посмотрим на простой пример обычной пользовательской формы, сохраненной как `login.gtpl` в папке Вашего проекта:
Имя пользователя: Пароль:
Эта форма отправит данные по адресу `/login` на сервер. После того, как пользователь нажмет кнопку "Войти", данные будут посланы на хэндлер `login`, зарегистрированный маршрутизатором сервера. Нам нужно знать, какой метод используется при этом - POST или GET? Это легко узнать при помощи пакета `http`. Давайте посмотрим, как обработать данные формы со страницы входа: package main import ( "fmt" "html/template" "log" "net/http" "strings" ) func sayhelloName(w http.ResponseWriter, r *http.Request) { r.ParseForm() // Анализирует переданные параметры url, затем анализирует пакет ответа для тела POST (тела запроса) // внимание: без вызова метода ParseForm последующие данные не будут получены fmt.Println(r.Form) // печатает информацию на сервере fmt.Println("Путь: ", r.URL.Path) fmt.Println("Схема: ", r.URL.Scheme) fmt.Println(r.Form["url_long"]) for k, v := range r.Form { fmt.Println("Ключ: ", k) fmt.Println("Значение: ", strings.Join(v, "")) } fmt.Fprintf(w, "Привет astaxie!") // пишет данные в ответ } func login(w http.ResponseWriter, r *http.Request) { fmt.Println("Метод:", r.Method) // получаем информацию о методе запроса if r.Method == "GET" { t, _ := template.ParseFiles("login.gtpl") t.Execute(w, nil) } else { //r.ParseForm() // логическая часть процесса входа fmt.Println("Пользователь:", r.Form["username"]) fmt.Println("Пароль:", r.Form["password"]) } } func main() { http.HandleFunc("/", sayhelloName) // устанавливаем правила маршрутизатора http.HandleFunc("/login", login) err := http.ListenAndServe(":9090", nil) // устанавливаем порт для прослушивания if err != nil { log.Fatal("ListenAndServe: ", err) } } Здесь мы используем `r.Method` для того, чтобы получить информацию о методе запроса, и нам возвращается метод HTTP -"GET", "POST", "PUT" и т.д. В функции `login` мы использовали метод `r.Method`, чтобы проверить, что это - страница входа или логика обработки информации о входе. Другими словами, мы проверяем, открыл ли пользователь страницу или уже заполнил форму и пытается войти. Сервер отображает страницу только в случае, если запрос идет посредством метода GET, и запускает логику обработки информации о входе, если запрос использует метод POST. Вы должны увидеть следующий интерфейс после открытия `http://127.0.0.1:9090/login` в браузере: ![](images/4.1.login.png?raw=true) Рисунок 4.1 Интерфейс входа пользователя Сервер ничего не напечатает, пока мы не введем имя пользователя и пароль, потому что хэндлер не будет анализировать данные, пока мы не вызовем `r.ParseForm()`. Давайте добавим `r.ParseForm()` перед `fmt.Println("username:", r.Form["username"])`, скомпилируем программу и вновь протестируем её. Вы обнаружите, что в этом случае информация стала печататься на стороне сервера. `r.Form` содержит все аргументы запроса, например, строку запроса в URL и данные в POST и PUT. Если в данных есть конфликты, например, параметры имеют одинаковое имя, сервер сохранит данные в срез из множества значений. Документация Go говорит о том, что Go сохраняет данные из запросов GET и POST в разных местах. Попробуйте изменить значение поля 'action' в форме `http://127.0.0.1:9090/login` на `http://127.0.0.1:9090/login?username=astaxie` в файле `login.gtpl`, протестируйте работу формы, и Вы увидите, что на стороне сервера вывелся срез значений: ![](images/4.1.slice.png?raw=true) Рисунок 4.2 Сервер печатает данные запроса Тип поля `request.Form` - это `url.Values`. Данные в нем сохраняются в формате `ключ=значение`. v := url.Values{} v.Set("name", "Ava") v.Add("friend", "Jess") v.Add("friend", "Sarah") v.Add("friend", "Zoe") // v.Encode() == "name=Ava&friend=Jess&friend=Sarah&friend=Zoe" fmt.Println(v.Get("name")) fmt.Println(v.Get("friend")) fmt.Println(v["friend"]) **Совет:** Запросы могут получать доступ к данным формы с использованием метода `FormValue()`. Например, можно вместо `r.Form["username"]` использовать `r.FormValue("username")`, и Go вызовет `r.ParseForm` автоматически. Отметим, что в случае наличия нескольких аргументов с одним и тем же именем этот метод вернет первое из значений, а в случае отсутствия такого аргумента вернет пустую строку. ## Ссылки - [Содержание](preface.md) - Предыдущий раздел: [Пользовательские формы](04.0.md) - Следующий раздел: [Проверка введенных данных](04.2.md)