diff --git a/README.md b/README.md index cbbad9c50..f7903b67f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Multiple Language Versions -* [(HTML - PDF) on GitBook](https://legacy.gitbook.com/book/astaxie/build-web-application-with-golang) +* [(HTML - PDF) on GitBook](https://astaxie.gitbooks.io/build-web-application-with-golang) * [Deutsch](de/preface.md) * [English](en/preface.md) * [Español](es/preface.md) diff --git a/en/02.3.md b/en/02.3.md index d47e0b6f5..d5ae48930 100644 --- a/en/02.3.md +++ b/en/02.3.md @@ -193,7 +193,7 @@ Use the `func` keyword to define a function. func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) { // function body // multi-value return - return value1, value2 + return output1, output2 } ``` We can extrapolate the following information from the example above. diff --git a/en/03.2.md b/en/03.2.md index b111db94a..66b8b988e 100644 --- a/en/03.2.md +++ b/en/03.2.md @@ -4,6 +4,7 @@ We've discussed that web applications are based on the HTTP protocol, and Go pro ## Use http package setup a web server +```go package main import ( @@ -33,6 +34,7 @@ We've discussed that web applications are based on the HTTP protocol, and Go pro log.Fatal("ListenAndServe: ", err) } } +``` After we execute the above code, the server begins listening to port 9090 in local host. diff --git a/en/04.2.md b/en/04.2.md index cb618900e..be3807b78 100644 --- a/en/04.2.md +++ b/en/04.2.md @@ -96,7 +96,7 @@ If we want to know whether the user is male or female, we may use a radio button ``` And we use the following code to validate the input: ```Go - slice:=[]int{1,2} + slice:=[]string{"1","2"} for _, v := range slice { if v == r.Form.Get("gender") { diff --git a/en/05.6.md b/en/05.6.md index 327c24822..59d14bad7 100644 --- a/en/05.6.md +++ b/en/05.6.md @@ -9,7 +9,7 @@ As the C language of the 21st century, Go has good support for NoSQL databases, redis is a key-value storage system like Memcached, that supports the string, list, set, zset(ordered set) and hash value types. There are some Go database drivers for redis: -- [https://github.com/garyburd/redigo](https://github.com/garyburd/redigo) +- [https://github.com/gomodule/redigo](https://github.com/gomodule/redigo) - [https://github.com/go-redis/redis](https://github.com/go-redis/redis) - [https://github.com/hoisie/redis](https://github.com/hoisie/redis) - [https://github.com/alphazero/Go-Redis](https://github.com/alphazero/Go-Redis) @@ -22,7 +22,7 @@ Let's see how to use the driver that redigo to operate on a database: import ( "fmt" - "github.com/garyburd/redigo/redis" + "github.com/gomodule/redigo/redis" "os" "os/signal" "syscall" diff --git a/ja/09.3.md b/ja/09.3.md index e3548cc4a..141d4cc56 100644 --- a/ja/09.3.md +++ b/ja/09.3.md @@ -1,5 +1,5 @@ # 9.3 XSS攻撃の回避 -インターネット技術の発展に伴って、現在のWebアプリケーションはどれも大量の動的なコンテンツを含ませることでユーザビリティを高めています。いわゆる動的なコンテンツとは、アプリケーション・プログラムがユーザの環境とユーザのリクエストに従って対応するコンテンツを出力することをいいます。動的なホームページは"クロスサイトスクリプティング攻撃(Cross Site Scripting, セキュリティ専門家は通常これを省略してXSSと呼びます)"の脅威を受ける可能性があります。性的なホームページは完全にこの影響を受けません。 +インターネット技術の発展に伴って、現在のWebアプリケーションはどれも大量の動的なコンテンツを含ませることでユーザビリティを高めています。いわゆる動的なコンテンツとは、アプリケーション・プログラムがユーザの環境とユーザのリクエストに従って対応するコンテンツを出力することをいいます。動的なホームページは"クロスサイトスクリプティング攻撃(Cross Site Scripting, セキュリティ専門家は通常これを省略してXSSと呼びます)"の脅威を受ける可能性があります。静的なホームページは完全にこの影響を受けません。 ## XSSとは何か XSS攻撃:クロスサイトスクリプティング(Cross-Site Scripting)。カスケーディングスタイルシート(Cascading Style Sheets, CSS)の省略と混同しないようにクロスサイトスクリプティングはXSSと省略されます。XSSはよく見かけるセキュリティホールの一種です。これは攻撃者が悪意のあるコードを他のユーザが使用しているページに埋め込むことを許してしまいます。多くの攻撃(一般には攻撃者と被害者のみに影響します)とは異なりXSSは第三者に及びます。すなわち、攻撃者、クライアントとWebアプリケーションです。XSSの攻撃目標はクライアントに保存されたcookieの奪取またはクライアントの身分を識別する慎重に扱うべき情報を使う他のページです。一旦合法的なユーザの情報が取得されると、攻撃者は合法的なユーザを装ってページに対してやりとりを行うことができるようになります。 diff --git a/ru/01.1.md b/ru/01.1.md index b488a6950..47a9254b7 100644 --- a/ru/01.1.md +++ b/ru/01.1.md @@ -78,7 +78,7 @@ ### Linux -Зайдите на [страницу загрузки](https://golang.org/dl/), выберите `go1.4.2.linux-386.tar.gz` для 32-битных систем или `go1.4.2.linux-amd64.tar.gz` для 64-битных. Предположим, Вы хотите установить Go в каталог `$GO_INSTALL_DIR`. Распакуйте `tar.gz` в этот каталог командой `tar zxvf go1.4.2.linux-amd64.tar.gz -C $GO_INSTALL_DIR`. Затем измените прееменную $PATH следующим образом: `export PATH=$PATH:$GO_INSTALL_DIR/go/bin`. Теперь откройте терминал и напечатайте `go`. Вы должны увидеть то же, что показано на рисунке 1.1. +Зайдите на [страницу загрузки](https://golang.org/dl/), выберите `go1.4.2.linux-386.tar.gz` для 32-битных систем или `go1.4.2.linux-amd64.tar.gz` для 64-битных. Предположим, Вы хотите установить Go в каталог `$GO_INSTALL_DIR`. Распакуйте `tar.gz` в этот каталог командой `tar zxvf go1.4.2.linux-amd64.tar.gz -C $GO_INSTALL_DIR`. Затем измените переменную $PATH следующим образом: `export PATH=$PATH:$GO_INSTALL_DIR/go/bin`. Теперь откройте терминал и напечатайте `go`. Вы должны увидеть то же, что показано на рисунке 1.1. ### Windows diff --git a/ru/01.3.md b/ru/01.3.md index 3e10e18c4..251f9a524 100644 --- a/ru/01.3.md +++ b/ru/01.3.md @@ -19,7 +19,7 @@ - Если в каталоге много файлов, но Вы хотите скомпилировать только один, Вам нужно добавить имя файла после `go build`. Например, `go build a.go`. Просто `go build` скомпилирует все файлы в каталоге. - Вы также можете указать имя исполняемого файла, который будет создан. Например, в проекте `mathapp` (раздел 1.2), команда `go build -o astaxie.exe` создаст `astaxie.exe` вместо `mathapp.exe`. Именем по умолчанию для исполняемого файла является имя каталога (если пакет не main) или название первого файла-исходника (если пакет - main). -(Согласно [The Go Programming Language Specification](https://golang.org/ref/spec) имя пакета должно следовать после слова `package` в первой строке исходного файла. Оно не обязательно должно быть таким же, как имя каталога, и имя исполняемого файла по умлочанию будет таким же, как и имя каталога.) +(Согласно [Спецификации Языка Программирования Go](https://golang.org/ref/spec) имя пакета должно следовать после слова `package` в первой строке исходного файла. Оно не обязательно должно быть таким же, как имя каталога, и имя исполняемого файла по умолчанию будет таким же, как и имя каталога.) - `go build` не работает с файлами, имя которых начинается на `_` или `.`. - Если Вам нужно несколько исходных файлов для каждой операционной системы, Вы можете в конце каждого имени файла добавить соответствующий суффикс ОС. Предположим, имеется несколько файлов для загрузки массивов. Можно назвать их следующим образом: @@ -55,7 +55,7 @@ ## go get -Эта команда служит для установки удаленных пакетов. На данный момент она поддерживает BitBucket, GitHub, Google Code и Launchpad. При запуске этой команды происходят вещи: первая - Go скачивает исходники пакетов, вторая - исполняется `go install`. Перед использованием этой команды убедитесь, что у Вас установлены соответствующие инструменты: +Эта команда служит для установки удаленных пакетов. На данный момент она поддерживает BitBucket, GitHub, Google Code и Launchpad. При запуске этой команды происходят следующие вещи: первая - Go скачивает исходники пакетов, вторая - исполняется `go install`. Перед использованием этой команды убедитесь, что у Вас установлены соответствующие инструменты: BitBucket (Mercurial Git) GitHub (git) @@ -81,11 +81,11 @@ ## godoc -Многие говорят, что никакая сторонняя документация для программирования на Go не нужна (вообще я одну сделал - [CHM](https://github.com/astaxie/godoc)). В Go существует мощная утилита для того, чтобы управлять документацией "из коробки". +Многие говорят, что никакая сторонняя документация для программирования на Go не нужна (вообще, я одну сделал - [CHM](https://github.com/astaxie/godoc)). В Go существует мощная утилита для того, чтобы управлять документацией "из коробки". Итак, как мы можем ознакомиться с информацией о пакете в документации? Например, если Вы хотите получить подробную информацию о пакете `builtin`, используйте команду `godoc builtin`. Подобным образом Вы можете воспользоваться `godoc net/http` для того, чтобы ознакомиться с документацией по пакету `http`. Если Вам нужно больше деталей об отдельных функциях, выполните `godoc fmt Printf` и `godoc -src fmt Printf`, чтобы увидеть исходный код функции . -Выполните `godoc -http=:8080`, затем откройте в браузере `127.0.0.1:8080`. Вы должны увидеть локальную версию сайта golang.org. Он покажет не только информацию о стандартных пакетах, но также о пакетах в Вашем `$GOPATH/pkg`. Это здорово для людей, которые страдают от Великого Китайского Файерволла. +Выполните `godoc -http=:8080`, затем откройте в браузере `127.0.0.1:8080`. Вы должны увидеть локальную версию сайта golang.org. Она покажет не только информацию о стандартных пакетах, но также о пакетах в Вашем `$GOPATH/pkg`. Это здорово для людей, которые страдают от Великого Китайского Файерволла. ## Другие утилиты diff --git a/ru/01.4.md b/ru/01.4.md index ce08f584b..5bccdd1bc 100644 --- a/ru/01.4.md +++ b/ru/01.4.md @@ -1,10 +1,10 @@ # 1.4 Инструменты разработки для Go -В этом разделе я ознакомлю Вас с несколькими средами разработки (IDE), которые помогут Вам более эффективно программировать. Они обладают такими возможностями как умное автодополнение и автоформатирование. Все они кроссплатформенные, поэтому шаги по настройке, которые я покажу, не будут слишком отличаться в зависимости от операционной системы, которую Вы используете. +В этом разделе я ознакомлю Вас с несколькими средами разработки (IDE), которые помогут Вам более эффективно программировать. Они обладают такими возможностями, как умное автодополнение и автоформатирование. Все они кроссплатформенные, поэтому шаги по настройке, которые я покажу, не будут слишком отличаться в зависимости от операционной системы, которую Вы используете. ## LiteIDE -LiteIDE - нетребовательный к ресурсам системы IDE с открытым исходным кодом, который предназначен для разработки проектов только на Go. Он разработан visualfc. +LiteIDE - нетребовательная к ресурсам системы IDE с открытым исходным кодом, которая предназначена для разработки проектов только на Go. Она разработана visualfc. ![](images/1.4.liteide.png?raw=true) @@ -20,7 +20,7 @@ LiteIDE - нетребовательный к ресурсам системы ID - Поддерживает разные среды компиляции - Поддерживает кросс-компиляцию проектов на Go - Управление проектами - - Представление досументации основано на $GOPATH + - Представление документации основано на $GOPATH - Система компиляции основана на $GOPATH - Документация API основана на $GOPATH - Редактор исходного кода Go @@ -48,7 +48,7 @@ LiteIDE - нетребовательный к ресурсам системы ID - Установите LiteIDE: - [Страница загрузки](http://code.google.com/p/golangide) - - [Исходные коды](https://github.com/visualfc/liteide) + - [Исходный код](https://github.com/visualfc/liteide) Сначала установите Go, затем скачайте версию LiteIDE, соответствующую Вашей операционной системе. Распакуйте скачанный пакет. diff --git a/ru/02.0.md b/ru/02.0.md index b34727abc..62a53a4a4 100644 --- a/ru/02.0.md +++ b/ru/02.0.md @@ -1,6 +1,6 @@ -# 2 Введение в Go +# 2. Введение в Go -Go - компилируемый системный язык программирования, и он относится к С-подобным языкам. Однако, скорость его компиляции намного выше. Он имеет всего 25 ключевых слов... даже меньше чем букв в английском алфавите! Давайте взглянем на эти ключевые слова прежде чем мы начнем. +Go - компилируемый системный язык программирования, и он относится к С-подобным языкам. Однако, скорость его компиляции намного выше. Он имеет всего 25 ключевых слов... даже меньше, чем букв в английском алфавите! Давайте взглянем на эти ключевые слова прежде, чем мы начнем. break default func interface select case defer go map struct @@ -8,7 +8,7 @@ Go - компилируемый системный язык программир const fallthrough if range type continue for import return var -В этой главе, я собираюсь научить вас основам Go. Вы обнаружите, насколько лаконичен язык Go, и как превосходна его архитектура. Программирование на Go может быть по-настоящему веселым. После того, как вы закончите эту главу, вы будете знакомы с упомянутыми ключевыми словами. +В этой главе я собираюсь научить вас основам Go. Вы увидите, насколько лаконичен язык Go, и как превосходна его архитектура. Программирование на Go может быть по-настоящему веселым. После того, как вы закончите эту главу, вы будете знакомы с упомянутыми ключевыми словами. ## Ссылки diff --git a/ru/02.1.md b/ru/02.1.md index 744d61eed..87a42de86 100644 --- a/ru/02.1.md +++ b/ru/02.1.md @@ -1,6 +1,6 @@ # 2.1 Привет, Go -Прежде чем мы начнем конструировать приложение на Go, нам необходимо научиться писать простые программы. Вы не сможете построить здание, не узнав, сперва, как проложить фундамент. Вследствие чего, в этом разделе мы изучим базовый синтакс для запуска простой программы. +Прежде, чем мы начнем конструировать приложение на Go, нам необходимо научиться писать простые программы. Вы не сможете построить здание, не узнав, сперва, как проложить фундамент. Вследствие чего, в этом разделе мы изучим базовый синтакс для запуска простой программы. ## Программа @@ -22,7 +22,7 @@ ## Объяснение -Во-первых программы в Go состоят из `package` (пакетов). +Во-первых, программы в Go состоят из `package` (пакетов). `package ` (В данном случае `package main`) говорит нам о том, что этот исходный файл принадлежит к `main` пакету. А ключевое слово `main`, что данный пакет должен компилироваться в программу, а не в пакет файлов с расширением `.a`. @@ -31,11 +31,11 @@ Чтобы вывести `Hello, world…`, мы вызвали функцию `Printf`. Эта функция находится в пакете `fmt`, поэтому нам надо импортировать этот пакет, что мы и делаем в третьей строчке кода - `import "fmt"`. Пакеты в Go похожи на аналогичные в Python, вот несколько преимуществ пакетов: -Модульность (разбить программу на несколько модулей) и повторное использование (каждый модуль может быть использован во множестве программ). Сейчас мы просто рассмотрели общее представление пакетов, и чуть позже напишем свой собственный пакет. +Модульность (разбиение программы на несколько модулей) и повторное использование (каждый модуль может быть использован во множестве программ). Сейчас мы просто рассмотрели общее представление пакетов, и чуть позже напишем свой собственный пакет. В пятой строке мы использовали ключевое слово `func` для определения функции `main`. Тело функции находится внутри `{}`, прямо как в C, C++ и Java. -Как вы видите она не принимает ни один аргумент. Мы научимся писать функции, принимающие аргументы всего через минуту, а также функции которые не возвращают значение или возращают несколько. +Как вы видите, она не принимает ни один аргумент. Мы научимся писать функции, принимающие аргументы всего через минуту, а также функции которые не возвращают значение или возращают несколько. В шестой строке мы вызываем функцию `Printf`, которая находится в пакете `fmt`. Она была вызвана, используя синтаксис `.` (`<имя пакета>.<имя функции>`), в Python-стиле. @@ -45,7 +45,7 @@ ## Заключение -Go использует `package` (пакет) для структурирования программ. Функция `main.main()` (эта функция находится в пакете `main`) входной пункт каждой программы. Go поддерживает стандарт UTF-8, так как один из создателей Go является также одним из создателей UTF-8, так что Go поддерживает множество языков с самого рождения. +Go использует `package` (пакет) для структурирования программ. Функция `main.main()` (эта функция находится в пакете `main`) - входной пункт каждой программы. Go поддерживает стандарт UTF-8, так как один из создателей Go является также одним из создателей UTF-8, так что Go поддерживает множество языков с самого рождения. ## Ссылки diff --git a/ru/02.2.md b/ru/02.2.md index 53335c4ac..5f085961c 100644 --- a/ru/02.2.md +++ b/ru/02.2.md @@ -51,7 +51,7 @@ _, b := 34, 35 -Если Вы определили переменную и не использовали ее нигде в своей программе, компилятор покажет Вам ошибку компиляции. Попробуйте откомпилировать следующий код и посмотрите, что будет: +Если Вы определили переменную и не использовали ее нигде в своей программе, компилятор покажет Вам ошибку компиляции. Попробуйте скомпилировать следующий код и посмотрите, что будет: package main @@ -105,7 +105,7 @@ Хотя int32 длиннее int8 и является тем же типом, что и int, нельзя использовать их в одним выражении. ( ***'c' здесь будет определена как переменная типа `int`*** ) -К типам с плавающей точкой относятся `float32` и `float64`; типа, называемого `float` в Go нет. `float64` используется по умолчанию при коротком объявлении. +К типам с плавающей точкой относятся `float32` и `float64`; типа, называемого `float`, в Go нет. `float64` используется по умолчанию при коротком объявлении. Это все? Нет! Go также поддерживает и комплексные числа. `complex128` (с 64-битной вещественной и 64-битной мнимыми частями) является комплексным числом по умолчанию, а если Вам нужны числа поменьше, есть `complex64` (с 32-битной вещественной и 32-битной нмимыми частями). Числа представлены в форме `RE+IMi`, где `RE` - вещественная часть, а `IM` - мнимая, последнее `i` - мнимая единица. Вот пример комплексного числа: @@ -115,7 +115,7 @@ ### Строки -Мы уже говорили о том, как Go использует кодировку UTF-8. Строки представлены двойными кавычками `""` или обратными кавычками ``` `` ```. +Мы уже говорили о том, что Go использует кодировку UTF-8. Строки представлены двойными кавычками `""` или обратными кавычками ``` `` ```. // Пример кода var frenchHello string // основная форма определения строки @@ -398,7 +398,7 @@ // Задаем карте начальное значение rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 } - // карта возвращает два значения. В качестве второго, если элемента с таким ключом не существует, 'ok' возвращает 'false', иначе - 'true'. + // карта возвращает два значения. В качестве второго, если элемента с таким ключом не существует, 'ok' принимает значение 'false', иначе - 'true'. csharpRating, ok := rating["C#"] if ok { fmt.Println("C# находится в карте, его рейтинг - ", csharpRating) diff --git a/ru/02.4.md b/ru/02.4.md index 5a94f1f00..97709031e 100644 --- a/ru/02.4.md +++ b/ru/02.4.md @@ -9,7 +9,7 @@ type person struct { age int } ``` -Вот так как легко определять `структуру`! +Вот так легко определять `структуру`! У нас есть два поля: diff --git a/ru/02.6.md b/ru/02.6.md index 3209f201b..ea20d4ca7 100644 --- a/ru/02.6.md +++ b/ru/02.6.md @@ -367,7 +367,7 @@ type ReadWriter interface { t := reflect.TypeOf(i) // получает мета-данные типа i в переменную t v := reflect.ValueOf(i) // получает значение типа i в переменную v ``` -После этого мы может конвертировать типы, полученные в результате рефлексии, для того, чтобы получить нужные нам значения. +После этого мы можем конвертировать типы, полученные в результате рефлексии, для того, чтобы получить нужные нам значения. ```Go var x float64 = 3.4 v := reflect.ValueOf(x) diff --git a/ru/02.7.md b/ru/02.7.md index eee7041c2..c5af95c34 100644 --- a/ru/02.7.md +++ b/ru/02.7.md @@ -91,7 +91,7 @@ runtime.Gosched() говорит процессору, что нужно исп ## Буферизованные каналы -Выше я говорил о небуферизованных каналах. В Go также есть буферизованные каналы, которые могут хранить больше, чем один элемент. Нарпимер, `ch := make(chan bool, 4)`, здесь мы создали канал, который может содержать 4 булевых элемента. Поэтому в этот канал мы можем послать до 4 булевых элементов, и горутина не заблокриуется, но она заблокируется, когда Вы попытаетесь послать в канал пятый элемент, и ни одна горутина его не примет. +Выше я говорил о небуферизованных каналах. В Go также есть буферизованные каналы, которые могут хранить больше, чем один элемент. Нарпимер, `ch := make(chan bool, 4)`, здесь мы создали канал, который может содержать 4 булевых элемента. Поэтому в этот канал мы можем послать до 4 булевых элементов, и горутина не заблокируется, но она заблокируется, когда Вы попытаетесь послать в канал пятый элемент, и ни одна горутина его не примет. ch := make(chan type, n) diff --git a/ru/03.0.md b/ru/03.0.md index 91baf4fb3..ffe01c5c4 100644 --- a/ru/03.0.md +++ b/ru/03.0.md @@ -1,6 +1,6 @@ -# 3 Основы Веба +# 3. Основы Веба -Основной причиной, по которой вы читаете эту книгу, является желание научиться создавать веб-приложения на языке Go. Как я уже говорил ранее, Go предоставляет много мощных пакетов, способных справляться с этой задачей, например пакет «http». Этот пакет поможет вам создавать web-приложения. Я объясню Вам все что вы должны знать о разработке веб-приложений в следующих главах, а сейчас мы поговорим о концепции Веба и о том как запускать веб-приложения в Go. +Основной причиной, по которой вы читаете эту книгу, является желание научиться создавать веб-приложения на языке Go. Как я уже говорил ранее, Go предоставляет много мощных пакетов, способных справляться с этой задачей, например пакет «http». Этот пакет поможет вам создавать web-приложения. Я объясню Вам все, что вы должны знать о разработке веб-приложений, в следующих главах, а сейчас мы поговорим о концепции Веба и о том, как запускать веб-приложения в Go. ## Ссылки diff --git a/ru/03.1.md b/ru/03.1.md index c0fa8d8f5..680d98453 100644 --- a/ru/03.1.md +++ b/ru/03.1.md @@ -1,4 +1,4 @@ -# Принципы работы веб +# 3.1 Принципы работы веб Каждый раз, когда Вы открываете браузер, вводите URL-адрес и нажимаете клавишу enter, вы видите красивые веб-страницы на вашем экране. Но знаете ли вы, что стоит за этим простым действием? @@ -35,7 +35,7 @@ URL расшифровывается как Uniform Resource Locator, в пер <параметры> данные, которые будут отправлены на сервер <якорь> якорь -DNS-это аббревиатура  Domain Name System - система доменных имен. Это система имен для компьютерных сетевых служб , которая преобразует доменное имя в фактические IP-адреса (своеобразный переводчик). +DNS - это аббревиатура Domain Name System - система доменных имен. Это система имен для компьютерных сетевых служб, которая преобразует доменное имя в фактические IP-адреса (своеобразный переводчик). ![](images/3.1.dns_hierachy.png?raw=true) @@ -70,7 +70,7 @@ HTTP является протоколом независимой обработ ### HTTP запрос (информация о браузере) -Все пакеты запросов состоят из трех частей: строка запроса, заголовок запроса и тело запроса. Между заголовкам запроса и телом запроса идет одна пустая строка. +Все пакеты запросов состоят из трех частей: строка запроса, заголовок запроса и тело запроса. Между заголовком запроса и телом запроса идет одна пустая строка. GET /domains/example/ HTTP/1.1 // request line: request method, URL, protocol and its version Host:www.iana.org // имя домена @@ -106,7 +106,7 @@ POST помещает данные в теле запроса, поскольк Content-Type: text/html // тип данных ответа Transfer-Encoding: chunked // это означает, что данные были отправлены фрагментами Connection: keep-alive // сохранить подключение - Content-Length: 90 // длинна тела (размер) + Content-Length: 90 // длина тела (размер) // пустая строка -Эта форма отправит данные по адресу `/login` на сервер. После того, как пользователь нажем кнопку "Войти", данные будут посланы на хэндлер `login`, зарегистрированный маршрутизатором сервера. Нам нужно знать, какой метод используется при этом - POST или GET? +Эта форма отправит данные по адресу `/login` на сервер. После того, как пользователь нажмет кнопку "Войти", данные будут посланы на хэндлер `login`, зарегистрированный маршрутизатором сервера. Нам нужно знать, какой метод используется при этом - POST или GET? Это легко узнать при помощи пакета `http`. Давайте посмотрим, как обработать данные формы со страницы входа: diff --git a/ru/04.3.md b/ru/04.3.md index 5e9caf41d..fb20343c4 100644 --- a/ru/04.3.md +++ b/ru/04.3.md @@ -1,6 +1,6 @@ # 4.3 Межсайтовый скриптинг -Для совершенствования взаимодействия с пользователем современные сайты содержат все больше динамического контента, что означает, что мы должны предоставлять информацию динамически в зависимости от поведения каждого пользователя. К сожалению, существует такое явление как "межсайтовый скриптинг" (известный как "XSS"), с помощью которого осуществляются постоянные атаки на динамические сайты, в то время как сайты со статическим содержимым этим атакам не подвержены. +Для совершенствования взаимодействия с пользователем современные сайты содержат все больше динамического контента, что означает, что мы должны предоставлять информацию динамически, в зависимости от поведения каждого пользователя. К сожалению, существует такое явление как "межсайтовый скриптинг" (известный как "XSS"), с помощью которого осуществляются постоянные атаки на динамические сайты, в то время как сайты со статическим содержимым этим атакам не подвержены. Злоумышленники посылают на сайты, подверженные межсайтовому скриптингу, скрипты на JavaScript, VBScript, ActiveX или Flash. Если скрипт удачно вторгся на сайт, пользовательская информация может быть похищена, а сайт наполнен спамом. Злоумышленники могут также изменить настройки пользователя на те, которые захотят. diff --git a/ru/04.5.md b/ru/04.5.md index ab69c9fcc..4bc1d03f8 100644 --- a/ru/04.5.md +++ b/ru/04.5.md @@ -1,8 +1,8 @@ # 4.5 Загрузка файлов -Предположим, у Вас есть веб-сайт наподобие Instagram, и Вы хотите, чтобы пользователи закачивали туда свои фортографии. Как можно реализовать эту функцию? +Предположим, у Вас есть веб-сайт наподобие Instagram, и Вы хотите, чтобы пользователи закачивали туда свои фотографии. Как можно реализовать эту функцию? -Для этого нужно добавить в форму, через которую будут закачиваться фотографии, свойство `enctype`. Оно имеет три значения: +Для этого нужно добавить в форму, через которую будут закачиваться фотографии, со свойством `enctype`. Оно имеет три значения: ``` application/x-www-form-urlencoded Кодировать все символы перед закачкой (по умолчанию). diff --git a/ru/04.6.md b/ru/04.6.md index 78350cbde..b11845385 100644 --- a/ru/04.6.md +++ b/ru/04.6.md @@ -8,4 +8,4 @@ - [Содержание](preface.md) - Предыдущий раздел: [Загрузка файлов](04.5.md) -- Следужщий раздел: [Базы данных](05.0.md) +- Следующий раздел: [Базы данных](05.0.md) diff --git a/ru/05.0.md b/ru/05.0.md index d3040ddaf..ef86fa9f0 100644 --- a/ru/05.0.md +++ b/ru/05.0.md @@ -1,8 +1,8 @@ -# 5 Базы данных +# 5. Базы данных Одним из ключевых аспектов веб разработки является использование баз данных. В базах данных можно хранить и обрабатывать почти все, например информацию о пользователях, продуктах, новостные списки и т.д. -Язык Go не имеет каких либо драйверов для баз данных, но у него есть драйвер интерфейса, определенный в пакете `database/sql`. На базе этого интерфейса разработчики могут легко создавать свои драйвера баз данных. В разделе 5.1 мы с вами рассмотрим структуру драйвера интерфеса в Go; в разделах 5.2 - 5.4 я покажу вам некоторые драйвера SQL баз данных; в разделе 5.5 я покажу ORM, которую я разработал базируясь на стандарте интерфейса `database/sql`, она совместима с большинством драйверов, включенных в интерфейс `database/sql` и предоставляет простой доступ к базам данных встиле языка Go. (***ORM (англ. Object-Relational Mapping, рус. объектно-реляционное отображение) — технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных».***) +Язык Go не имеет каких либо драйверов для баз данных, но у него есть драйвер интерфейса, определенный в пакете `database/sql`. На базе этого интерфейса разработчики могут легко создавать свои драйвера баз данных. В разделе 5.1 мы с вами рассмотрим структуру драйвера интерфеса в Go; в разделах 5.2 - 5.4 я покажу вам некоторые драйвера SQL баз данных; в разделе 5.5 я покажу ORM, которую я разработал базируясь на стандарте интерфейса `database/sql`, она совместима с большинством драйверов, включенных в интерфейс `database/sql` и предоставляет простой доступ к базам данных в стиле языка Go. (***ORM (англ. Object-Relational Mapping, рус. объектно-реляционное отображение) — технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных».***) NoSQL является горячей темой в последние годы. Большинство новых сайтов решили использовать базу данных NoSQL в качестве основной базы данных, а не только для использования кэша. Я расскажу подробнее о двух NoSQL базах данных - MongoDB и Redis в разделе 5.6. diff --git a/ru/05.1.md b/ru/05.1.md index b84c9f70d..437642611 100644 --- a/ru/05.1.md +++ b/ru/05.1.md @@ -46,7 +46,7 @@ drivers[name] = driver Open(name string) (Conn, error) } -`Conn` - это одноразовое соединение. Это означает, что его можно использовать только один раз в одной горутине. Следующй код вызовет исключение: +`Conn` - это одноразовое соединение. Это означает, что его можно использовать только один раз в одной горутине. Следующий код вызовет исключение: ... go goroutineA (Conn) // запрос @@ -148,7 +148,7 @@ driver.Rows - это интерфейс для возвращения резул type Value interface{} -`Value` должно быть содержать значения, совместимые с драйвером, или быть nil, поэтому оно должно быть одним из следующих типов: +`Value` должно содержать значения, совместимые с драйвером, или быть nil, поэтому оно должно быть одним из следующих типов: int64 float64 diff --git a/ru/05.2.md b/ru/05.2.md index a2699e180..1fdf6a775 100644 --- a/ru/05.2.md +++ b/ru/05.2.md @@ -1,6 +1,6 @@ # 5.2 MySQL -Комплекс северного программного обеспечения LAMP последние годы очень популярен в интернете. Буква М в данном акрониме означает MySQL. MySQL является наиболее известной базой данных с открытым исходным кодом. Она проста в использовании, поэтому ее часто используют в бэкенде множества веб-сайтов. +Комплекс серверного программного обеспечения LAMP последние годы очень популярен в интернете. Буква М в данном акрониме означает MySQL. MySQL является наиболее известной базой данных с открытым исходным кодом. Она проста в использовании, поэтому ее часто используют в бэкенде множества веб-сайтов. ## Драйвера MySQL diff --git a/ru/05.3.md b/ru/05.3.md index 945380a4b..6c7642806 100644 --- a/ru/05.3.md +++ b/ru/05.3.md @@ -1,6 +1,6 @@ # 5.3 SQLite -SQLite это открытая встраиваемая реляционная база данных. Она автономна, не требует конфигурации и является полноценной СУБД. Ее основные характеристики это: высокая портативность, простота использования, эффективность и надежость. В большинстве случаев вам нужен только двоичный файл SQLite для создания, подключения и эксплуатации базы данных. Если вы ищите встраиваемое решение СУБД, вам стоит рассмотреть SQLite. По сути SQLite является версией Access с открыты исходным кодом. +SQLite - это открытая, встраиваемая, реляционная база данных. Она автономна, не требует конфигурации и является полноценной СУБД. Ее основные характеристики это: высокая портативность, простота использования, эффективность и надежность. В большинстве случаев вам нужен только двоичный файл SQLite для создания, подключения и эксплуатации базы данных. Если вы ищите встраиваемое решение СУБД, вам стоит рассмотреть SQLite. По сути SQLite является версией Access с открытым исходным кодом. ## Драйвера SQLite diff --git a/ru/05.4.md b/ru/05.4.md index 7ef1f1370..3d839e228 100644 --- a/ru/05.4.md +++ b/ru/05.4.md @@ -1,6 +1,6 @@ # 5.4 PostgreSQL -PostgreSQL - свободная объектно-реляционная система управления базами данных доступная для множества платформ, включая Linux, FreeBSD, Solaris, Microsoft Windows и Mac OS X. Выпускается под собственной MIT-подобной лицензией. В отличие от MySQL, она разработана и позиционируется для использования в корпоративном сегменте, как Oracle. Так что PostgreSQL - это хороший выбор для использования в корпоративных проектах. +PostgreSQL - свободная, объектно-реляционная система управления базами данных, доступная для множества платформ, включая Linux, FreeBSD, Solaris, Microsoft Windows и Mac OS X. Выпускается под собственной MIT-подобной лицензией. В отличие от MySQL, она разработана и позиционируется для использования в корпоративном сегменте, как Oracle. Так что PostgreSQL - это хороший выбор для использования в корпоративных проектах. ## Драйвера PostgreSQL diff --git a/ru/06.0.md b/ru/06.0.md index c690d349d..1d367cca6 100644 --- a/ru/06.0.md +++ b/ru/06.0.md @@ -1,8 +1,8 @@ -# 6 Хранение данных и сессии +# 6. Хранение данных и сессии -Хорошие впечатления пользователей - важная тема в web-разработке, однако тот факт, что HTTP является протоколом без сохранения состояния, кажется противоречит этому тезису. Как мы можем контролировать процесс просмотра web-страниц пользователями? Классическим решением является использование куки(cookies) и сессий. Куки хранятся на стороне клиента, а сессии, с уникальным идентификатором для каждого пользователя, на стороне сервера.Обратите внимание, что идентификаторы сессий можно хранить не только в URL, и куки-файлах, но также в базе данных, что намного более безопасно, но может сказаться на производительности приложения. +Хорошие впечатления пользователей - важная тема в web-разработке, однако тот факт, что HTTP является протоколом без сохранения состояния, кажется, противоречит этому тезису. Как мы можем контролировать процесс просмотра web-страниц пользователями? Классическим решением является использование куки(cookies) и сессий. Куки хранятся на стороне клиента, а сессии, с уникальным идентификатором для каждого пользователя, на стороне сервера. Обратите внимание, что идентификаторы сессий можно хранить не только в URL и куки-файлах, но также и в базе данных, что намного более безопасно, но может сказаться на производительности приложения. -В разделе 6.1 мы будем говорит о различиях между сессиями и куки-файлами. В разделе 6.2 вы узнаете, как использовать сессии в Go с помощью реализации менеджера сессий. В разделе +В разделе 6.1 мы будем говорить о различиях между сессиями и куки-файлами. В разделе 6.2 вы узнаете, как использовать сессии в Go с помощью реализации менеджера сессий. В разделе 6.3 мы будем говорить о способах угона(hijacking) сессий и как его предотвратить, в том случае, если вы знаете, что идентификатор сессии может быть сохранен где угодно. Менеджер сеансов, который мы реализуем в разделе 6.3 будет хранить сессии в памяти, но если вам необходимо масштабировать приложение, чтобы обеспечить общий доступ к сессиям, то всегда лучше хранить их непосредственно в базе данных. Мы поговорим об этом подробнее в разделе 6.4 diff --git a/th/01.1.md b/th/01.1.md index 1e09d4478..8ecfb1e5a 100644 --- a/th/01.1.md +++ b/th/01.1.md @@ -39,7 +39,7 @@ sudo apt-get install gcc libc6-dev บน Windows สามารถทำสิ่งเดียวกันนี้โดยใช้คำสั่ง `all.bat` แทน -หากใช้ระบบปฎิบัติการ Windows ตัวติดตั้งจะทำการตั้งค่าตัวแปร environment ให้โดยอัตโนมัติ แต่่่หากเป็นระบบที่คล้าย Unix นั้น เราต้องตั้งค่าเหล่านั้นด้วยตัวเอง ดังนี้ ( ***หากเป็น Go เวอร์ชั่นที่มากกว่า 1.0 เราไม่จำเป็นต้องตั้งค่า $GOBIN โดยจะถูกตั้งค่าให้อย่างอัตโนมัติโดยอ้างอิงจาก $GOROOT/bin ซึ่งจะได้พูดถึงในบทถัดไป*** ) +หากใช้ระบบปฎิบัติการ Windows ตัวติดตั้งจะทำการตั้งค่าตัวแปร environment ให้โดยอัตโนมัติ แต่หากเป็นระบบที่คล้าย Unix นั้น เราต้องตั้งค่าเหล่านั้นด้วยตัวเอง ดังนี้ ( ***หากเป็น Go เวอร์ชั่นที่มากกว่า 1.0 เราไม่จำเป็นต้องตั้งค่า $GOBIN โดยจะถูกตั้งค่าให้อย่างอัตโนมัติโดยอ้างอิงจาก $GOROOT/bin ซึ่งจะได้พูดถึงในบทถัดไป*** ) export GOROOT=$HOME/go export GOBIN=$GOROOT/bin diff --git a/zh/01.2.md b/zh/01.2.md index d878aed0a..c385cb36d 100644 --- a/zh/01.2.md +++ b/zh/01.2.md @@ -29,7 +29,7 @@ go mod tidy 安装指定包: ``` -go get -v github/com/go-ego/gse@v0.60.0-rc4.2 +go get -v github.com/go-ego/gse@v0.60.0-rc4.2 ``` ### 更新依赖 diff --git a/zh/03.3.md b/zh/03.3.md index 79dd97f43..f01643788 100644 --- a/zh/03.3.md +++ b/zh/03.3.md @@ -1,4 +1,5 @@ # 3.3 Go如何使得Web工作 + 前面小节介绍了如何通过Go搭建一个Web服务,我们可以看到简单应用一个net/http包就方便的搭建起来了。那么Go在底层到底是怎么做的呢?万变不离其宗,Go的Web服务工作也离不开我们第一小节介绍的Web工作方式。 ## web工作方式的几个概念 @@ -33,46 +34,117 @@ Handler:处理请求和生成返回信息的处理逻辑 - 如何接收客户端请求? - 如何分配handler? -前面小节的代码里面我们可以看到,Go是通过一个函数`ListenAndServe`来处理这些事情的,这个底层其实这样处理的:初始化一个server对象,然后调用了`net.Listen("tcp", addr)`,也就是底层用TCP协议搭建了一个服务,然后监控我们设置的端口。 +前面小节的代码里面我们可以看到,Go是通过一个函数`ListenAndServe`来处理这些事情的,其实现源码如下: + +```Go +func ListenAndServe(addr string, handler Handler) error { + server := &Server{Addr: addr, Handler: handler} + return server.ListenAndServe() +} + +``` + +`ListenAndServe`会初始化一个`sever`对象,然后调用了`Server`对象的方法`ListenAndServe`。其源码如下: + +```Go +func (srv *Server) ListenAndServe() error { + if srv.shuttingDown() { + return ErrServerClosed + } + addr := srv.Addr + if addr == "" { + addr = ":http" + } + ln, err := net.Listen("tcp", addr) + if err != nil { + return err + } + return srv.Serve(ln) +} + +``` + +`ListenAndServe`调用了`net.Listen("tcp", addr)`,也就是底层用TCP协议搭建了一个服务,最后调用`src.Serve`监控我们设置的端口。监控之后如何接收客户端的请求呢? + +`Serve`的具体实现如下(为突出重点,仅展示关键代码),通过下面的分析源码我们可以看到客户端请求的具体处理过程: -下面代码来自Go的http包的源码,通过下面的代码我们可以看到整个的http处理过程: ```Go func (srv *Server) Serve(l net.Listener) error { - defer l.Close() - var tempDelay time.Duration // how long to sleep on accept failure + ... + + ctx := context.WithValue(baseCtx, ServerContextKey, srv) for { - rw, e := l.Accept() - if e != nil { - if ne, ok := e.(net.Error); ok && ne.Temporary() { - if tempDelay == 0 { - tempDelay = 5 * time.Millisecond - } else { - tempDelay *= 2 - } - if max := 1 * time.Second; tempDelay > max { - tempDelay = max - } - log.Printf("http: Accept error: %v; retrying in %v", e, tempDelay) - time.Sleep(tempDelay) - continue + rw, err := l.Accept() + ... + + connCtx := ctx + if cc := srv.ConnContext; cc != nil { + connCtx = cc(connCtx, rw) + if connCtx == nil { + panic("ConnContext returned nil") } - return e } tempDelay = 0 - c, err := srv.newConn(rw) - if err != nil { - continue - } - go c.serve() + c := srv.newConn(rw) + c.setState(c.rwc, StateNew, runHooks) // before Serve can return + go c.serve(connCtx) } } ``` -监控之后如何接收客户端的请求呢?上面代码执行监控端口之后,调用了`srv.Serve(net.Listener)`函数,这个函数就是处理接收客户端的请求信息。这个函数里面起了一个`for{}`,首先通过Listener接收请求,其次创建一个Conn,最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个conn去服务:`go c.serve()`。这个就是高并发体现了,用户的每一次请求都是在一个新的goroutine去服务,相互不影响。 -那么如何具体分配到相应的函数来处理请求呢?conn首先会解析request:`c.readRequest()`,然后获取相应的handler:`handler := c.server.Handler`,也就是我们刚才在调用函数`ListenAndServe`时候的第二个参数,我们前面例子传递的是nil,也就是为空,那么默认获取`handler = DefaultServeMux`,那么这个变量用来做什么的呢?对,这个变量就是一个路由器,它用来匹配url跳转到其相应的handle函数,那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了`http.HandleFunc("/", sayhelloName)`嘛。这个作用就是注册了请求`/`的路由规则,当请求uri为"/",路由就会转到函数sayhelloName,DefaultServeMux会调用ServeHTTP方法,这个方法内部其实就是调用sayhelloName本身,最后通过写入response的信息反馈到客户端。 +这个函数里面起了一个`for{}`,首先通过Listener接收请求:`l.Accept()`,其次创建一个Conn:`c := srv.newConn(rw)`,最后单独开了一个goroutine,把这个请求的数据当做参数扔给这个conn去服务:`go c.serve(connCtx)`。这个就是高并发体现了,用户的每一次请求都是在一个新的goroutine去服务,相互不影响。 +那么如何具体分配到相应的函数来处理请求呢?我们继续分析conn的`serve`方法,其源码如下(为突出重点,仅展示关键代码): + +```Go +func (c *conn) serve(ctx context.Context) { + ... + + ctx, cancelCtx := context.WithCancel(ctx) + c.cancelCtx = cancelCtx + defer cancelCtx() + + c.r = &connReader{conn: c} + c.bufr = newBufioReader(c.r) + c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) + + for { + w, err := c.readRequest(ctx) + ... + + // HTTP cannot have multiple simultaneous active requests.[*] + // Until the server replies to this request, it can't read another, + // so we might as well run the handler in this goroutine. + // [*] Not strictly true: HTTP pipelining. We could let them all process + // in parallel even if their responses need to be serialized. + // But we're not going to implement HTTP pipelining because it + // was never deployed in the wild and the answer is HTTP/2. + serverHandler{c.server}.ServeHTTP(w, w.req) + w.cancelCtx() + ... + + } +} +``` + +conn首先会解析request:`w, err := c.readRequest(ctx)`, 然后获取相应的handler去处理请求:`serverHandler{c.server}.ServeHTTP(w, w.req)`,`ServeHTTP`的具体实现如下: + +```Go +func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { + handler := sh.srv.Handler + if handler == nil { + handler = DefaultServeMux + } + if req.RequestURI == "*" && req.Method == "OPTIONS" { + handler = globalOptionsHandler{} + } + handler.ServeHTTP(rw, req) +} +``` + +`sh.srv.Handler`就是我们刚才在调用函数`ListenAndServe`时候的第二个参数,我们前面例子传递的是nil,也就是为空,那么默认获取`handler = DefaultServeMux`,那么这个变量用来做什么的呢?对,这个变量就是一个路由器,它用来匹配url跳转到其相应的handle函数,那么这个我们有设置过吗?有,我们调用的代码里面第一句不是调用了`http.HandleFunc("/", sayhelloName)`嘛。这个作用就是注册了请求`/`的路由规则,当请求uri为"/",路由就会转到函数sayhelloName,DefaultServeMux会调用ServeHTTP方法,这个方法内部其实就是调用sayhelloName本身,最后通过写入response的信息反馈到客户端。 详细的整个流程如下图所示: @@ -82,8 +154,8 @@ func (srv *Server) Serve(l net.Listener) error { 至此我们的三个问题已经全部得到了解答,你现在对于Go如何让Web跑起来的是否已经基本了解了呢? - ## links - * [目录]() - * 上一节: [GO搭建一个简单的web服务](<03.2.md>) - * 下一节: [Go的http包详解](<03.4.md>) + +* [目录]() +* 上一节: [GO搭建一个简单的web服务](<03.2.md>) +* 下一节: [Go的http包详解](<03.4.md>) diff --git a/zh/05.6.md b/zh/05.6.md index ed7503828..5709f36f1 100644 --- a/zh/05.6.md +++ b/zh/05.6.md @@ -9,7 +9,7 @@ redis是一个key-value存储系统。和Memcached类似,它支持存储的val 目前应用redis最广泛的应该是新浪微博平台,其次还有Facebook收购的图片社交网站instagram。以及其他一些有名的[互联网企业](http://redis.io/topics/whos-using-redis) Go目前支持redis的驱动有如下 -- https://github.com/garyburd/redigo (推荐) +- https://github.com/gomodule/redigo (推荐) - https://github.com/go-redis/redis - https://github.com/hoisie/redis - https://github.com/alphazero/Go-Redis @@ -27,7 +27,7 @@ import ( "syscall" "time" - "github.com/garyburd/redigo/redis" + "github.com/gomodule/redigo/redis" ) var (