Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
108 lines (82 sloc) 6.93 KB

4.1 Работа с формами

Перед тем, как начать, давайте посмотрим на простой пример обычной пользовательской формы, сохраненной как login.gtpl в папке Вашего проекта:

<html>
<head>
<title></title>
</head>
<body>
<form action="/login" method="post">
	Имя пользователя:<input type="text" name="username">
	Пароль:<input type="password" name="password">
	<input type="submit" value="Войти">
</form>
</body>
</html>

Эта форма отправит данные по адресу /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 в браузере:

Рисунок 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, протестируйте работу формы, и Вы увидите, что на стороне сервера вывелся срез значений:

Рисунок 4.2 Сервер печатает данные запроса

Тип поля request.Form - это url.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"])

Совет: Запросы могут получать доступ к данным формы с использованием метода FormValue(). Например, можно вместо r.Form["username"] использовать r.FormValue("username"), и Go вызовет r.ParseForm автоматически. Отметим, что в случае наличия нескольких аргументов с одним и тем же именем этот метод вернет первое из значений, а в случае отсутствия такого аргумента вернет пустую строку.

Ссылки