Skip to content

Latest commit

 

History

History
87 lines (60 loc) · 6.29 KB

File metadata and controls

87 lines (60 loc) · 6.29 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.

Ссылки