# 3.3 Как Go работает с веб В предыдущем разделе мы научились использовать пакет `net/http` для создания простого веб-сервера. В этом разделе мы вернемся к принципам работы Веб, которые рассматривали ранее, но уже в контексте языка Go. ## Некоторые понятия, необходимые для понимания принципов работы веб-сервера. Request: запрос данных от пользователей, включая методы POST, GET, Cookie и URL Response: данные ответа от сервера. Conn: соединения между клиентами и серверами. Handler: логика обработки запроса и генерация ответа. ## механизм работы пакета http На следующей картинке показано как работает веб-сервер Go. ![](images/3.3.http.png?raw=true) Рисунок 3.9 работа http сервера 1. Сервер создает прослушивающий сокет на определенном порту и ожидает подключения клиентов. 2. Сервер принимает запросы от клиентов. 3. Обрабатывает запросы посредством чтения HTTP заголовков (если используется метод POST, читаются данные из тела запроса) и отправляет их обработчикам. Наконец, сокет возвращает данные клиентам. Для того чтобы точно узнать, как Go работает с Веб - необходимо получить ответ на три вопроса: - Как прослушивается порт? - Как принимаются клиентские соединения? - Как распределяются обработчики? В предыдущем разделе мы видели, что Go использует функцию `ListenAndServe` для инициализации объекта сервера и вызова метода `net.Listen("tcp", addr)`, устанавливающего TCP прослушку на заданный адрес и порт. Давайте посмотрим на исходный код пакета `http`. //используется код Go версии 1.1.2 func (srv *Server) Serve(l net.Listener) error { defer l.Close() var tempDelay time.Duration // время сна в случае сбоя 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 } return e } tempDelay = 0 c, err := srv.newConn(rw) if err != nil { continue } go c.serve() } } Как происходит прием клиентских запросов? В исходном коде мы видим, что происходит вызов метода `srv.Serve(net.Listener)` для управления клиентскими запросами. В теле функции бесконечный цикл `for{}` принимает запросы, создает новое соединение, запускает новую горутину `go c.serve()` и передает в нее данные запроса. Так Go поддерживает высокий параллелизм, за счет того, что все горутины являются независимыми. Теперь ответим на вопрос как используются конкретные функции для управления запросами? Сначала метод `conn` парсит запрос возвращаемый `c.ReadRequest()`, а затем получает соответствующий обработчик: `handler := c.server.Handler`, который, в совою очередь, передается в качестве второго аргумента при вызове метода `ListenAndServe`. В нашем сервере мы использовали `nil`, поэтому Go использует обработчик по умолчанию: `handler = DefaultServeMux`. Возникает вопрос - что здесь делает `DefaultServeMux`? DefaultServeMux - это переменная, содержащая указатель на текущий маршрутизатор, который вызывает обработчики для заданных URL-адресов. Разве мы его устанавливали? Ответ - да. Помните в первой строке нашего веб-сервера мы использовали `http.HandleFunc("/", sayhelloName)`. Эта функция регистрирует правила маршрутизации для пути "/". Когда URL-адрес запроса соответствует «/», маршрутизатор вызывает функцию «sayhelloName». DefaultServeMux вызывает ServerHTTP для получения функции обработчика соответствующего заданному пути. В нашем случае он вызывает «sayhelloName». Наконец, сервер отвечает клиенту. Подробное описание процесса: ![](images/3.3.illustrator_Ru.png?raw=true) Рисунок 3.10 воркфлоу обработки HTTP-запроса Теперь, я думаю, вы разобрались с тем, как работают веб-сервера Go. ## Ссылки - [Содержание](preface.md) - Предыдущий раздел: [Создание простого веб-сервера](03.2.md) - Следующий раздел: [Внутренний мир пакет http](03.4.md)