Merge pull request #713 from kasmanavt/section3
add ru translation for chapter 03.4, 03.5, change preface
This commit is contained in:
137
ru/03.4.md
Normal file
137
ru/03.4.md
Normal file
@@ -0,0 +1,137 @@
|
||||
# 3.4 Внутренний мир пакета http
|
||||
|
||||
В предыдущих разделах мы узнали о том, как работает Веб и немного затронули работу с пакетом `http`. В данном разделе мы изучим две основные функции этого пакета: Conn и ServeMux.
|
||||
|
||||
## Использование горутин в функции Conn
|
||||
|
||||
В отличи от обычных HTTP серверов, Go использует гоурутины при каждом обращении к функции Conn. За счет эго обеспечивается высокая производительность и параллельная обработка.
|
||||
|
||||
Go использует следующий код для ожидания новых подключений от клиента:
|
||||
|
||||
c, err := srv.newConn(rw)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
go c.serve()
|
||||
|
||||
Как вы видите, горутины создаются для каждого подключения. При этом в горутину передается обработчик, способный читать данные из запросов.
|
||||
|
||||
## Настраиваемые ServeMux
|
||||
|
||||
В предыдущем разделе, при рассмотрении метода conn.server, мы использовали роутер по умолчанию. Основная задача роутера - передать данные запроса конкретному обработчику.
|
||||
|
||||
Структура роутера по умолчанию:
|
||||
|
||||
type ServeMux struct {
|
||||
mu sync.RWMutex // здесь используются мьютексы для синхронизации параллельных потоков
|
||||
m map[string]muxEntry // правила маршрутизации, каждая строка ссылается на обработчик
|
||||
}
|
||||
|
||||
Структура muxEntry:
|
||||
|
||||
type muxEntry struct {
|
||||
explicit bool // exact match or not
|
||||
h Handler
|
||||
}
|
||||
|
||||
Интерфейс Handler:
|
||||
|
||||
type Handler interface {
|
||||
ServeHTTP(ResponseWriter, *Request) // реализация маршрутизации
|
||||
}
|
||||
|
||||
`Handler` - это интерфейс, однако, функция `sayhelloName` не реализует этот интерфейс. Почему, в таком случае, мы смогли использовать ее в качестве обработчика? Потому, что в пакете `http` существует другой тип `HandlerFunc`. В нашем нашем сервере из раздела 3.2 при вызове `HandlerFunc` происходит автоматическое приведение нашей функции `sayhelloName` к интерфейсу `Handler`. Это равносильно вызову `HandlerFunc(f)`, при этом `f` будет принудительно приведена к типу `HandlerFunc`.
|
||||
|
||||
type HandlerFunc func(ResponseWriter, *Request)
|
||||
|
||||
// ServeHTTP вызывает f(w, r).
|
||||
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
|
||||
f(w, r)
|
||||
}
|
||||
|
||||
Как маршрутизатор вызывает обработчики после установки правил?
|
||||
|
||||
Маршрутизатор вызывает `mux.handler.ServeHTTP(w, r)` при получении запросов. Другими словами, он вызывает `ServeHTTP` интерфейсы обработчиков.
|
||||
|
||||
Давайте посмотрим как работает `mux.handler`.
|
||||
|
||||
func (mux *ServeMux) handler(r *Request) Handler {
|
||||
mux.mu.RLock()
|
||||
defer mux.mu.RUnlock()
|
||||
|
||||
// Host-зависимый шаблон, имеет приоритет над универсальным
|
||||
h := mux.match(r.Host + r.URL.Path)
|
||||
if h == nil {
|
||||
h = mux.match(r.URL.Path)
|
||||
}
|
||||
if h == nil {
|
||||
h = NotFoundHandler()
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
Маршрутизатор использует URL-адрес в качестве ключа для поиска соответствующего обработчика, который сохранен в карте и вызовов handler.ServeHTTP для выполнения функций обработки данных.
|
||||
|
||||
Теперь вы должны понимать принципы работы роутера. Фактически, Go поддерживает настраиваемые роутеры. Второй аргумент функции `ListenAndServe` необходим для конфигурации настраиваемого роутера с типом `Handler`. Таким образом любой роутер реализует интерфейс `Handler`.
|
||||
|
||||
Следующий пример покажет, как реализовать простой роутер.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type MyMux struct {
|
||||
}
|
||||
|
||||
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/" {
|
||||
sayhelloName(w, r)
|
||||
return
|
||||
}
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
func sayhelloName(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "Hello myroute!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
mux := &MyMux{}
|
||||
http.ListenAndServe(":9090", mux)
|
||||
}
|
||||
|
||||
## Исполнение кода по шагам
|
||||
|
||||
Давайте посмотрим на поток выполнения.
|
||||
|
||||
- Вызывается `http.HandleFunc`.
|
||||
1. Вызывается `HandleFunc` из `DefaultServeMux`.
|
||||
2. Вызывается `Handle` из `DefaultServeMux`.
|
||||
3. Добавляются правила маршрутизации в карту `map[string]muxEntry` из `DefaultServeMux`.
|
||||
- Вызывается `http.ListenAndServe(":9090", nil)`.
|
||||
1. Создается экземпляр `Server`.
|
||||
2. Вызывается `ListenAndServe` для `Server`.
|
||||
3. Вызывается `net.Listen("tcp", addr)` для прослушки порта.
|
||||
4. Запускается бесконечный цикл, в теле которого происходит прием запросов.
|
||||
5. Создается экземпляр Conn и запускаются горутины для каждого запроса: `go c.serve()`.
|
||||
6. Читаются данные запроса: `w, err := c.readRequest()`.
|
||||
7. Проверяется существует ли обработчик и если обработчика нет используется `DefaultServeMux`.
|
||||
8. Вызывается `ServeHTTP` для обработчика.
|
||||
9. Исполняется код в `DefaultServeMux` в нашем случае.
|
||||
10. Выбирается обработчик, соответсвующий URL, и исполняется код обработчика: `mux.handler.ServeHTTP(w, r)`
|
||||
11. Как выбирается обработчик:
|
||||
A. Проверяются правила маршрутизации по данному URL.
|
||||
B. Вызывается `ServeHTTP` в данном обработчике, если он есть.
|
||||
C. В противном случае вызывается `ServeHTTP` для `NotFoundHandler`.
|
||||
|
||||
## Ссылки
|
||||
|
||||
- [Содержание](preface.md)
|
||||
- Предыдущий раздел: [Как Go работает с веб](03.3.md)
|
||||
- Следующий раздел: [Итоги раздела](03.5.md)
|
||||
|
||||
|
||||
12
ru/03.5.md
Normal file
12
ru/03.5.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# 3.5 Итоги главы
|
||||
|
||||
В этой главе мы познакомились с тем как работает HTTP, разрешение имен DNS и как создать простой веб-сервер на языке Go. После этого мы обсудили как Go создает веб-сервер на примере исходных кодов пакета `net/http`.
|
||||
|
||||
Я надеюсь, вы узнали гораздо больше о веб-разработке и поняли, что создавать веб-приложения в Go достаточно легко.
|
||||
|
||||
## Ссылки
|
||||
|
||||
- [Содержание](preface.md)
|
||||
- Предыдущий раздел: [Внутренний мир пакета http](03.4.md)
|
||||
- Следующая глава: [Пользовательские формы](04.0.md)
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
- 2.6. [Интерфейсы](02.6.md)
|
||||
- 2.7. [Многопоточность](02.7.md)
|
||||
- 2.8. [Итоги раздела](02.8.md)
|
||||
- 3.[Web foundation](03.0.md)
|
||||
- 3.1. [Web working principles](03.1.md)
|
||||
- 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.[Основы Веба](03.0.md)
|
||||
- 3.1. [Принципы работы веб](03.1.md)
|
||||
- 3.2. [Создание простого веб-сервера](03.2.md)
|
||||
- 3.3. [Как Go работает с веб](03.3.md)
|
||||
- 3.4. [Внутренний мир пакета http](03.4.md)
|
||||
- 3.5. [Итоги раздела](03.5.md)
|
||||
- 4.[Пользовательские формы](04.0.md)
|
||||
- 4.1. [Работа с формами](04.1.md)
|
||||
@@ -26,7 +26,7 @@
|
||||
- 4.4. [Дублирование отправки](04.4.md)
|
||||
- 4.5. [Загрузка файлов](04.5.md)
|
||||
- 4.6. [Итоги раздела](04.6.md)
|
||||
- 5.[Database](05.0.md)
|
||||
- 5.[Базы данных](05.0.md)
|
||||
- 5.1. [database/sql interface](05.1.md)
|
||||
- 5.2. [MySQL](05.2.md)
|
||||
- 5.3. [SQLite](05.3.md)
|
||||
|
||||
Reference in New Issue
Block a user