add ru translation for 03.4
This commit is contained in:
136
ru/03.4.md
Normal file
136
ru/03.4.md
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
# 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 // because of concurrency, we have to use mutex here
|
||||||
|
m map[string]muxEntry // router rules, every string mapping to a handler
|
||||||
|
}
|
||||||
|
|
||||||
|
Структура muxEntry:
|
||||||
|
|
||||||
|
type muxEntry struct {
|
||||||
|
explicit bool // exact match or not
|
||||||
|
h Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
Интерфейс Handler:
|
||||||
|
|
||||||
|
type Handler interface {
|
||||||
|
ServeHTTP(ResponseWriter, *Request) // routing implementer
|
||||||
|
}
|
||||||
|
|
||||||
|
`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-specific pattern takes precedence over generic ones
|
||||||
|
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)
|
||||||
|
|
||||||
Reference in New Issue
Block a user