Skip to content

Latest commit

 

History

History
87 lines (60 loc) · 6.3 KB

File metadata and controls

87 lines (60 loc) · 6.3 KB

3.3 Как Go работает с веб

В предыдущем разделе мы научились использовать пакет net/http для создания простого веб-сервера. В этом разделе мы вернемся к принципам работы Веб, которые рассматривали ранее, но уже в контексте языка Go.

Некоторые понятия, необходимые для понимания принципов работы веб-сервера.

Request: запрос данных от пользователей, включая методы POST, GET, Cookie и URL

Response: данные ответа от сервера.

Conn: соединения между клиентами и серверами.

Handler: логика обработки запроса и генерация ответа.

Механизм работы пакета http

На следующей картинке показано, как работает веб-сервер Go.

Рисунок 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». Наконец, сервер отвечает клиенту.

Подробное описание процесса:

Рисунок 3.10 воркфлоу обработки HTTP-запроса

Теперь, я думаю, вы разобрались с тем, как работают веб-сервера Go.

Ссылки