From 1090aa00c17964486c07a992c4cd26aa01c1bf41 Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Thu, 10 Sep 2015 10:36:39 +0200 Subject: [PATCH 1/8] 04.0 --- ru/04.0.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 ru/04.0.md diff --git a/ru/04.0.md b/ru/04.0.md new file mode 100644 index 00000000..5c6146d6 --- /dev/null +++ b/ru/04.0.md @@ -0,0 +1,24 @@ +# 4 Пользовательские формы + +Пользовательские формы очень часто используются при разработке веб-приложений. Они дают возможность клиенту и серверу устанавливать коммуникацию друг с другом. Если вы - веб-разработчик, Вы должны быть хорошо знакомыми с веб-формами; если Вы - программист на C/C++, Вы можете спросить - что такое пользовательская форма? + +Форма - это область, которая содержит элементы формы. Пользхователь может вносить информацию в элементы формы такие как текстовые поля, выпадающие списки, радиокнопки, чекбоксы и т.д. Для определения формы используется тэг `
`. + + + ... + элементы формы, через которые вносится информация + ... +
+ +В Go уже есть множество удобных функций для того, чтобы взаимодействовать с пользовательскими формами. Можно легкол получить данные из формы в запросе HTTP, они легко интегрируются в Ваши веб-приложения. В разделе 4.1 мы собираемся поговорить о том, как обрабатывать данные из форм в Go. Также,поскольку нельзя доверять любым аднным, приходящим со стороны клиента, нужно сначала проверить их перед тем, как использовать. В разделе 4.2 мы поговорим о том, как проверить данные, пришедшие из формы. + +We say that HTTP is stateless. How can we identify that certain forms are from the same user? And how do we make sure that one form can only be submitted once? We'll look at some details concerning cookies (a cookie is information that can be saved on the client side and added to the request header when the request is sent to the server) in both sections 4.3 and 4.4. +Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные лишь один раз? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4. + +Еще один важный случай использования форм - загрузка файлов. В разделе 4.5 Вы научитесь, как это делать, осуществляя контроль размера файла перед тем, как его загрузить, средствами Go. + +## Ссылки + +- [Содержание](preface.md) +- Предыдущий раздел: [Итоги главы 3](03.5.md) +- Следующий раздел: [](04.1.md) From db24f0e184b3bf51f195b3d9e4052e3c9c18f03b Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Thu, 10 Sep 2015 10:45:01 +0200 Subject: [PATCH 2/8] 04.0 --- ru/04.0.md | 5 ++--- ru/preface.md | 16 ++++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/ru/04.0.md b/ru/04.0.md index 5c6146d6..be34d7ed 100644 --- a/ru/04.0.md +++ b/ru/04.0.md @@ -2,7 +2,7 @@ Пользовательские формы очень часто используются при разработке веб-приложений. Они дают возможность клиенту и серверу устанавливать коммуникацию друг с другом. Если вы - веб-разработчик, Вы должны быть хорошо знакомыми с веб-формами; если Вы - программист на C/C++, Вы можете спросить - что такое пользовательская форма? -Форма - это область, которая содержит элементы формы. Пользхователь может вносить информацию в элементы формы такие как текстовые поля, выпадающие списки, радиокнопки, чекбоксы и т.д. Для определения формы используется тэг `
`. +Форма - это область, которая содержит элементы формы. Пользователь может вносить информацию в элементы формы, такие как текстовые поля, выпадающие списки, радиокнопки, чекбоксы и т.д. Для определения формы используется тэг ``. ... @@ -10,9 +10,8 @@ ...
-В Go уже есть множество удобных функций для того, чтобы взаимодействовать с пользовательскими формами. Можно легкол получить данные из формы в запросе HTTP, они легко интегрируются в Ваши веб-приложения. В разделе 4.1 мы собираемся поговорить о том, как обрабатывать данные из форм в Go. Также,поскольку нельзя доверять любым аднным, приходящим со стороны клиента, нужно сначала проверить их перед тем, как использовать. В разделе 4.2 мы поговорим о том, как проверить данные, пришедшие из формы. +В Go уже есть множество удобных функций для того, чтобы взаимодействовать с пользовательскими формами. Можно легко получить данные из формы в запросе HTTP, они легко интегрируются в Ваши веб-приложения. В разделе 4.1 мы собираемся поговорить о том, как обрабатывать данные из форм в Go. Также, поскольку нельзя доверять любым данным, приходящим со стороны клиента, нужно сначала проверить их перед тем, как использовать. В разделе 4.2 мы поговорим о том, как проверить данные, пришедшие из формы. -We say that HTTP is stateless. How can we identify that certain forms are from the same user? And how do we make sure that one form can only be submitted once? We'll look at some details concerning cookies (a cookie is information that can be saved on the client side and added to the request header when the request is sent to the server) in both sections 4.3 and 4.4. Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные лишь один раз? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4. Еще один важный случай использования форм - загрузка файлов. В разделе 4.5 Вы научитесь, как это делать, осуществляя контроль размера файла перед тем, как его загрузить, средствами Go. diff --git a/ru/preface.md b/ru/preface.md index c512586f..c02bc35c 100644 --- a/ru/preface.md +++ b/ru/preface.md @@ -18,14 +18,14 @@ - 3.2. [Build a simple web server](03.2.md) - 3.3. [How Go works with web](03.3.md) - 3.4. [Get into http package](03.4.md) - - 3.5. [Summary](03.5.md) -- 4.[User form](04.0.md) - - 4.1. [Process form inputs](04.1.md) - - 4.2. [Verification of inputs](04.2.md) - - 4.3. [Cross site scripting](04.3.md) - - 4.4. [Duplicate submissions](04.4.md) - - 4.5. [File upload](04.5.md) - - 4.6. [Summary](04.6.md) + - 3.5. [Итоги раздела](03.5.md) +- 4.[Пользовательские формы](04.0.md) + - 4.1. [Работа с формами](04.1.md) + - 4.2. [Проверка введенных данных](04.2.md) + - 4.3. [Межсайтовый скриптинг](04.3.md) + - 4.4. [Дублирование отправки](04.4.md) + - 4.5. [Загрузка файлов](04.5.md) + - 4.6. [Итоги раздела](04.6.md) - 5.[Database](05.0.md) - 5.1. [database/sql interface](05.1.md) - 5.2. [MySQL](05.2.md) From 7f993ce8806b11582bbcc41d565f74d0656ad01f Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 11:28:19 +0200 Subject: [PATCH 3/8] 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) From e8365264b403086bb45574842244618464266e7b Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 11:54:25 +0200 Subject: [PATCH 4/8] 04.1 --- ru/04.1.md | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/ru/04.1.md b/ru/04.1.md index a95a5e3f..ce5d4baf 100644 --- a/ru/04.1.md +++ b/ru/04.1.md @@ -15,7 +15,7 @@ -Эта форма отправит данные по адресу `/login` на сервер. После того, как пользователь нажем кнопку "Войти", дата будет послана на хэндлер `login`, зарегистрированный маршрутизатором сервера. Нам нужно знать, какой метод используется при этом - POST или GET? +Эта форма отправит данные по адресу `/login` на сервер. После того, как пользователь нажем кнопку "Войти", данные будут посланы на хэндлер `login`, зарегистрированный маршрутизатором сервера. Нам нужно знать, какой метод используется при этом - POST или GET? Это легко узнать при помощи пакета `http`. Давайте посмотрим, как обработать данные формы со страницы входа: @@ -30,9 +30,9 @@ ) func sayhelloName(w http.ResponseWriter, r *http.Request) { - r.ParseForm() //Анализирует переданные параметры url, затем анализирует пакет ответа для тела POST (тела запроса) - // внимание: без вызова метода ParseForm послежующие данные не будут получены - fmt.Println(r.Form) // печатает информацию на сервере. + 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"]) @@ -44,7 +44,7 @@ } func login(w http.ResponseWriter, r *http.Request) { - fmt.Println("Метод:", r.Method) //получаем информацию о методе запроса + fmt.Println("Метод:", r.Method) // получаем информацию о методе запроса if r.Method == "GET" { t, _ := template.ParseFiles("login.gtpl") t.Execute(w, nil) @@ -68,9 +68,9 @@ Здесь мы используем `r.Method` для того, чтобы получить информацию о методе запроса, и нам возвращается метод HTTP -"GET", "POST", "PUT" и т.д. -В функции `login` мы использовали метод `r.Method`, чтобы проверить, это страница входа или логика обработки информации о входе. Другими словами, мы проверяем, открыл ли пользователь страницу или уже пытается войти. Сервер отображает страницу только в случае, если запрос идет посредством метода GET, и запускает логику обработки информации о входе, если запрос использует метод POST. +В функции `login` мы использовали метод `r.Method`, чтобы проверить, что это - страница входа или логика обработки информации о входе. Другими словами, мы проверяем, открыл ли пользователь страницу или уже заполнил форму и пытается войти. Сервер отображает страницу только в случае, если запрос идет посредством метода GET, и запускает логику обработки информации о входе, если запрос использует метод POST. -Вы должны увидеть следующий интерфейс после открытия `http://127.0.0.1:9090/login` в броузере: +Вы должны увидеть следующий интерфейс после открытия `http://127.0.0.1:9090/login` в браузере: ![](images/4.1.login.png?raw=true) @@ -78,16 +78,15 @@ Сервер ничего не напечатает, пока мы не введем имя пользователя и пароль, потому что хэндлер не будет анализировать данные, пока мы не вызовем `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. +Попробуйте изменить значение поля '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) -Figure 4.2 Server prints request data +Рисунок 4.2 Сервер печатает данные запроса -The type of `request.Form` is `url.Value`. It saves data with the format `key=value`. +Тип поля `request.Form` - это `url.Value`. Данные в нем сохраняются в формате `ключ=значение`. v := url.Values{} v.Set("name", "Ava") @@ -99,10 +98,10 @@ The type of `request.Form` is `url.Value`. It saves data with the format `key=va 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. +**Совет** Запросы могут получать доступ к данным формы с использованием метода `FormValue()`. Например, можно вместо `r.Form["username"]` использовать `r.FormValue("username")`, и Go вызовет `r.ParseForm` автоматически. Отметим, что в случае наличия нескольких аргументов с одним и тем же именем этот метод вернет первое из значений, а в случае отсутствия такого аргумента вернет пустую строку. -## Links +## Ссылки -- [Directory](preface.md) -- Previous section: [User form](04.0.md) -- Next section: [Verification of inputs](04.2.md) +- [Содержание](preface.md) +- Предыдущий раздел: [Пользовательские формы](04.0.md) +- Следующий раздел: [Проверка введенных данных](04.2.md) From 4334bfaf65ebbf128e924496c9b5abedb81a5d91 Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 12:02:03 +0200 Subject: [PATCH 5/8] 04.1 --- ru/04.0.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ru/04.0.md b/ru/04.0.md index be34d7ed..28c0a2e7 100644 --- a/ru/04.0.md +++ b/ru/04.0.md @@ -1,8 +1,8 @@ # 4 Пользовательские формы -Пользовательские формы очень часто используются при разработке веб-приложений. Они дают возможность клиенту и серверу устанавливать коммуникацию друг с другом. Если вы - веб-разработчик, Вы должны быть хорошо знакомыми с веб-формами; если Вы - программист на C/C++, Вы можете спросить - что такое пользовательская форма? +Пользовательские формы очень часто используются при разработке веб-приложений. Они дают возможность клиенту и серверу устанавливать коммуникацию друг с другом. Если вы - веб-разработчик, Вы должны быть хорошо знакомы с веб-формами; если Вы - программист на C/C++, Вы можете спросить - что такое пользовательская форма? -Форма - это область, которая содержит элементы формы. Пользователь может вносить информацию в элементы формы, такие как текстовые поля, выпадающие списки, радиокнопки, чекбоксы и т.д. Для определения формы используется тэг `
`. +Форма - это область, которая содержит элементы формы. Пользователь может вносить информацию в элементы формы, такие как текстовые поля, выпадающие списки, радиокнопки, чекбоксы и т.д. Для определения формы используется тэг ``: ... @@ -12,7 +12,7 @@ В Go уже есть множество удобных функций для того, чтобы взаимодействовать с пользовательскими формами. Можно легко получить данные из формы в запросе HTTP, они легко интегрируются в Ваши веб-приложения. В разделе 4.1 мы собираемся поговорить о том, как обрабатывать данные из форм в Go. Также, поскольку нельзя доверять любым данным, приходящим со стороны клиента, нужно сначала проверить их перед тем, как использовать. В разделе 4.2 мы поговорим о том, как проверить данные, пришедшие из формы. -Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные лишь один раз? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4. +Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные за один раз лишь однажды? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4. Еще один важный случай использования форм - загрузка файлов. В разделе 4.5 Вы научитесь, как это делать, осуществляя контроль размера файла перед тем, как его загрузить, средствами Go. @@ -20,4 +20,4 @@ - [Содержание](preface.md) - Предыдущий раздел: [Итоги главы 3](03.5.md) -- Следующий раздел: [](04.1.md) +- Следующий раздел: [Работа с формами](04.1.md) From 22bb644de318731f754178d99a2dbad726e53251 Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 12:03:47 +0200 Subject: [PATCH 6/8] 04.1 --- ru/04.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ru/04.0.md b/ru/04.0.md index 28c0a2e7..3c46b63c 100644 --- a/ru/04.0.md +++ b/ru/04.0.md @@ -12,7 +12,7 @@ В Go уже есть множество удобных функций для того, чтобы взаимодействовать с пользовательскими формами. Можно легко получить данные из формы в запросе HTTP, они легко интегрируются в Ваши веб-приложения. В разделе 4.1 мы собираемся поговорить о том, как обрабатывать данные из форм в Go. Также, поскольку нельзя доверять любым данным, приходящим со стороны клиента, нужно сначала проверить их перед тем, как использовать. В разделе 4.2 мы поговорим о том, как проверить данные, пришедшие из формы. -Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные за один раз лишь однажды? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4. +Говорится, что HTTP - это протокол без сохранения состояния. Так как проверить, что данные из формы пришли от того же пользователя? И как можно быть уверенным, что одна форма может послать данные за один раз лишь единожды? Мы рассмотрим некоторые детали, касающиеся кук (куки - это информация, сохраняемая на стороне клиента и добавляемая в заголовок запроса, посылаемый на сервер) в разделах 4.3 и 4.4. Еще один важный случай использования форм - загрузка файлов. В разделе 4.5 Вы научитесь, как это делать, осуществляя контроль размера файла перед тем, как его загрузить, средствами Go. From 103edbb16d783933eb2f07f290105fe6831495e8 Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 12:09:31 +0200 Subject: [PATCH 7/8] 04.1 --- ru/04.1.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ru/04.1.md b/ru/04.1.md index ce5d4baf..42f10e10 100644 --- a/ru/04.1.md +++ b/ru/04.1.md @@ -49,7 +49,7 @@ t, _ := template.ParseFiles("login.gtpl") t.Execute(w, nil) } else { - r.ParseForm() + //r.ParseForm() // логическая часть процесса входа fmt.Println("Пользователь:", r.Form["username"]) fmt.Println("Пароль:", r.Form["password"]) @@ -57,7 +57,7 @@ } func main() { - http.HandleFunc("/", sayhelloName) // устанавливаем правило маршрутизатора + http.HandleFunc("/", sayhelloName) // устанавливаем правила маршрутизатора http.HandleFunc("/login", login) err := http.ListenAndServe(":9090", nil) // устанавливаем порт для прослушивания if err != nil { @@ -78,9 +78,9 @@ Сервер ничего не напечатает, пока мы не введем имя пользователя и пароль, потому что хэндлер не будет анализировать данные, пока мы не вызовем `r.ParseForm()`. Давайте добавим `r.ParseForm()` перед `fmt.Println("username:", r.Form["username"])`, скомпилируем программу и вновь протестируем её. Вы обнаружите, что в этом случае информация стала печататься на стороне сервера. -`r.Form` содержит все аргументы запроса, например, сторку запроса в URL и данные в POST и PUT. Если в данных есть конфликты, например, параметры имеют одинаковое имя, сервер сохранит данные в срез из множества значений. Документация Go говорит о том, что Go сохраняет данные из запросов GET и POST в разных местах. +`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`, протестируйте работу формы, и Вы увидите, что на стороне сервера вывелся срез значений. +Попробуйте изменить значение поля '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) @@ -98,7 +98,7 @@ fmt.Println(v.Get("friend")) fmt.Println(v["friend"]) -**Совет** Запросы могут получать доступ к данным формы с использованием метода `FormValue()`. Например, можно вместо `r.Form["username"]` использовать `r.FormValue("username")`, и Go вызовет `r.ParseForm` автоматически. Отметим, что в случае наличия нескольких аргументов с одним и тем же именем этот метод вернет первое из значений, а в случае отсутствия такого аргумента вернет пустую строку. +**Совет:** Запросы могут получать доступ к данным формы с использованием метода `FormValue()`. Например, можно вместо `r.Form["username"]` использовать `r.FormValue("username")`, и Go вызовет `r.ParseForm` автоматически. Отметим, что в случае наличия нескольких аргументов с одним и тем же именем этот метод вернет первое из значений, а в случае отсутствия такого аргумента вернет пустую строку. ## Ссылки From 1a5e9009f531eec111166706d1153e2e64b790d5 Mon Sep 17 00:00:00 2001 From: Slava Zgordan Date: Mon, 21 Sep 2015 12:24:07 +0200 Subject: [PATCH 8/8] 04.1 --- ru/04.2.md | 141 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 ru/04.2.md diff --git a/ru/04.2.md b/ru/04.2.md new file mode 100644 index 00000000..b46ca24f --- /dev/null +++ b/ru/04.2.md @@ -0,0 +1,141 @@ +# 4.2 Verification of inputs + +One of the most important principles in web development is that you cannot trust anything from client side user forms. You have to verify all incoming data before use it. Many websites are affected by this problem, which is simple yet crucial. + +There are two ways of verify form data that are commonly used. One is JavaScript verification in the front-end, and the other is server verification in the back-end. In this section, we are going to talk about server side verification in web development. + +## Required fields + +Sometimes we require that users input some fields but they don't, for example in the previous section when we required a username. You can use the `len` function to get the length of a field in order to ensure that users have entered this information. + + if len(r.Form["username"][0])==0{ + // code for empty field + } + +`r.Form` treats different form element types differently when they are blank. For empty textboxes, text areas and file uploads, it returns an empty string; for radio buttons and check boxes, it doesn't even create the corresponding items. Instead, you will get errors if you try to access it. Therefore, it's safer to use `r.Form.Get()` to get field values since it will always return empty if the value does not exist. On the other hand, `r.Form.Get()` can only get one field value at a time, so you need to use `r.Form` to get the map of values. + +## Numbers + +Sometimes you only need numbers for the field value. For example, let's say that you require the age of a user in integer form only, i.e 50 or 10, instead of "old enough" or "young man". If we require a positive number, we can convert the value to the `int` type first, then process it. + + getint,err:=strconv.Atoi(r.Form.Get("age")) + if err!=nil{ + // error occurs when convert to number, it may not a number + } + + // check range of number + if getint >100 { + // too big + } + +Another way to do this is using regular expressions. + + if m, _ := regexp.MatchString("^[0-9]+$", r.Form.Get("age")); !m { + return false + } + +For high performance purposes, regular expressions are not efficient, however simple regular expressions are usually fast enough. If you are familiar with regular expressions, it's a very convenient way to verify data. Notice that Go uses [RE2](http://code.google.com/p/re2/wiki/Syntax), so all UTF-8 characters are supported. + +## Chinese + +Sometimes we need users to input their Chinese names and we have to verify that they all use Chinese rather than random characters. For Chinese verification, regular expressions are the only way. + + if m, _ := regexp.MatchString("^[\\x{4e00}-\\x{9fa5}]+$", r.Form.Get("realname")); !m { + return false + } + +## English letters + +Sometimes we need users to input only English letters. For example, we require someone's English name, like astaxie instead of asta谢. We can easily use regular expressions to perform our verification. + + if m, _ := regexp.MatchString("^[a-zA-Z]+$", r.Form.Get("engname")); !m { + return false + } + +## E-mail address + +If you want to know whether users have entered valid E-mail addresses, you can use the following regular expression: + + if m, _ := regexp.MatchString(`^([\w\.\_]{2,10})@(\w{1,}).([a-z]{2,4})$`, r.Form.Get("email")); !m { + fmt.Println("no") + }else{ + fmt.Println("yes") + } + +## Drop down list + +Let's say we require an item from our drop down list, but instead we get a value fabricated by hackers. How do we prevent this from happening? + +Suppose we have the following ` + + + + + +We can use the following strategy to sanitize our input: + + slice:=[]string{"apple","pear","banana"} + + for _, v := range slice { + if v == r.Form.Get("fruit") { + return true + } + } + return false + +All the functions I've shown above are in my open source project for operating on slices and maps: [https://github.com/astaxie/beeku](https://github.com/astaxie/beeku) + +## Radio buttons + +If we want to know whether the user is male or female, we may use a radio button, returning 1 for male and 2 for female. However, some little kid who just read his first book on HTTP, decides to send to you a 3. Will your program have have exception? As you can see, we need to use the same method as we did for our drop down list to make sure that only expected values are returned by our radio button. + + Male + Female + +And we use following code to verify the input: + + slice:=[]int{1,2} + + for _, v := range slice { + if v == r.Form.Get("gender") { + return true + } + } + return false + +## Check boxes + +Suppose there are some check boxes for user interests, and that you don't want extraneous values here either. + + Football + Basketball + Tennis + +In this case, the sanitization is a little bit different than verifying the button and check box inputs since here we get a slice from the check boxes. + + slice:=[]string{"football","basketball","tennis"} + a:=Slice_diff(r.Form["interest"],slice) + if a == nil{ + return true + } + + return false + +## Date and time + +Suppose you want users to input valid dates or times. Go has the `time` package for converting year, month and day to their corresponding times. After that, it's easy to check it. + + t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) + fmt.Printf("Go launched at %s\n", t.Local()) + +After you have the time, you can use the `time` package for more operations, depending on your needs. + +In this section, we've discussed some common methods for verifying form data server side. I hope that you now understand more about data verification in Go, especially how to use regular expressions to your advantage. + +## Links + +- [Directory](preface.md) +- Previous section: [Process form inputs](04.1.md) +- Next section: [Cross site scripting](04.3.md)