Что происходит, когда вы вводите URL в адресную строку браузера и нажимаете Enter?

Ответ

Это классический вопрос, который охватывает весь цикл веб-запроса. Процесс можно разбить на следующие этапы:

  1. Поиск IP-адреса (DNS-запрос): Браузер должен преобразовать доменное имя (например, example.com) в IP-адрес. Поиск происходит по цепочке:

    • Кэш браузера
    • Кэш операционной системы (файл hosts)
    • Кэш роутера
    • DNS-сервер вашего интернет-провайдера (ISP)
    • Рекурсивный запрос к корневым DNS-серверам.
  2. Установка TCP-соединения: После получения IP-адреса браузер устанавливает TCP-соединение с сервером. Этот процесс известен как трехстороннее рукопожатие (3-way handshake):

    • SYN: Клиент отправляет пакет SYN (synchronize) на сервер.
    • SYN-ACK: Сервер отвечает пакетом SYN-ACK (synchronize-acknowledgment).
    • ACK: Клиент подтверждает получение пакетом ACK (acknowledgment). Соединение установлено.
  3. TLS-рукопожатие (если используется HTTPS): Для установки безопасного соединения поверх TCP происходит TLS-рукопожатие. Клиент и сервер договариваются о версии протокола, выбирают алгоритмы шифрования и обмениваются ключами для шифрования всего последующего трафика.

  4. Отправка HTTP-запроса: Браузер отправляет HTTP-запрос на сервер. Запрос включает:

    • Стартовую строку: метод (GET, POST), путь (/index.html), версия протокола (HTTP/1.1).
    • Заголовки (Headers): Host, User-Agent, Accept, Cookie и другие.
    • Тело запроса (Body): (опционально) данные формы, JSON и т.д., обычно для POST или PUT запросов.
  5. Обработка запроса на сервере: Сервер (например, написанный на Go) получает запрос и обрабатывает его:

    • Принимает соединение и парсит HTTP-запрос.
    • Маршрутизатор (роутер) направляет запрос соответствующему обработчику (handler).
    • Обработчик выполняет бизнес-логику: обращается к базе данных, другим сервисам, выполняет вычисления.
    • Генерируется HTTP-ответ.

    Пример простого сервера на Go:

    package main
    
    import (
        "fmt"
        "log"
        "net/http"
    )
    
    func handler(w http.ResponseWriter, r *http.Request) {
        log.Printf("Received request for: %sn", r.URL.Path)
        fmt.Fprintf(w, "Hello, World!")
    }
    
    func main() {
        http.HandleFunc("/", handler)
        log.Println("Starting server on :8080")
        if err := http.ListenAndServe(":8080", nil); err != nil {
            log.Fatal(err)
        }
    }
  6. Отправка HTTP-ответа: Сервер отправляет ответ браузеру. Ответ содержит:

    • Статус-код: 200 OK, 404 Not Found, 500 Internal Server Error и т.д.
    • Заголовки: Content-Type, Content-Length, Set-Cookie и т.д.
    • Тело ответа: HTML-страница, JSON, изображение и т.д.
  7. Рендеринг страницы браузером: Браузер получает ответ и:

    • Парсит HTML для построения DOM-дерева.
    • Парсит CSS для построения CSSOM-дерева.
    • Объединяет их для создания Render Tree.
    • Выполняет компоновку (Layout) и отрисовку (Paint) пикселей на экране.
    • Загружает и выполняет JavaScript-код.