From 88c79e53a8cc39f0760101b037c56f369ca1c784 Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 11:28:19 +0200 Subject: [PATCH] 04.1 --- ru/04.1.md | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 ru/04.1.md diff --git a/ru/04.1.md b/ru/04.1.md new file mode 100644 index 00000000..a95a5e3f --- /dev/null +++ b/ru/04.1.md @@ -0,0 +1,108 @@ +# 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` contains all of the request arguments, for instance the query-string in the URL and the data in POST and PUT. If the data has conflicts, for example parameters that have the same name, the server will save the data into a slice with multiple values. The Go documentation states that Go will save the data from GET and POST requests in different places. +`r.Form` содержит все аргументы запроса, например, сторку запроса в URL и данные в POST и PUT. Если в данных есть конфликты, например, параметры имеют одинаковое имя, сервер сохранит данные в срез из множества значений. Документация Go говорит о том, что Go сохраняет данные из запросов GET и POST в разных местах. + +Try changing the value of the action in the form `http://127.0.0.1:9090/login` to `http://127.0.0.1:9090/login?username=astaxie` in the `login.gtpl` file, test it again, and you will see that the slice is printed on the server side. + +![](images/4.1.slice.png?raw=true) + +Figure 4.2 Server prints request data + +The type of `request.Form` is `url.Value`. It saves data with the format `key=value`. + + 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"]) + +**Tips** Requests have the ability to access form data using the `FormValue()` method. For example, you can change `r.Form["username"]` to `r.FormValue("username")`, and Go calls `r.ParseForm` automatically. Notice that it returns the first value if there are arguments with the same name, and it returns an empty string if there is no such argument. + +## Links + +- [Directory](preface.md) +- Previous section: [User form](04.0.md) +- Next section: [Verification of inputs](04.2.md)