Протокол как выглядит код
Перейти к содержимому

Протокол как выглядит код

  • автор:

# Сетевые протоколы и веб-сервер

. В тексте вы найдете ссылки на соответствующие видео-лекции.

# Что происходит при HTTP-запросе

Службы и сервисы, задействованные при работе с HTTP:

  • Браузер анализирует введенный URL и извлекает имя хоста (например, ya.ru ).
  • Используя систему DNS, браузер преобразует домен в ip адрес ( ya.ru становится 87.250.250.242 ).
  • Устанавливает TCP соединение с web-сервером.
  • Если протокол https, устанавливает TLS соединение поверх TCP.
  • Формирует HTTP запрос, отправляет его.
  • Получает HTTP-ответ с содержимым страницы (кодом HTML).
  • Браузер закрывает соединение (для HTTP/1.0).
  • Идет процесс парсинга и отображения документа.

С помощью утилиты curl

, можно увидеть необработанные браузером запросы и ответы:

Результат будет примерно таким:

Сетевые протоколы объединяются в стэк: одни предоставляют свои возможности другим:

Client HTTP/TLS — браузер Client TCP/IP — ОС пользователя

Server HTTP/TLS — веб-сервер Server TCP/IP — ОС сервера

Синие пунктирные стрелки — это не фактические вызовы. Мы не можем напрямую обратится к HTTP-сервера от клиента. Нужно спуститься по иерархии протоколов до IP (на самом деле еще ниже, IP это тоже надстройка над более низкоуровневыми протоколами).

Говоря, что данные передаются по HTTP, мы подразумеваем, что используется стек протоколов.

DNS (Domain Name System) — это распределенная база данных, хранящая информацию о доменах, в первую очередь отображение доменных имен на IP адреса машин, обслуживающих эти домены.

DNS — пожалуй, самая высоконагруженная база данных в мире. Она распределена по многим серверам (разделена на части для снижения нагрузки).

Пространство доменных имен:

. — самый корневой домен. Его обычно опускают в адресах.

База DNS разделена на зоны. Каждая зона обслуживается одной организацией:

Обработка DNS-запроса. Преобразование DNS в IP-адрес — это одна из функций ОС. Для этого в ОС нужен настроенный DNS-сервер в настройках интернета (зачастую предоставляет провайдер).

Для получения IP-адреса dobro.mail.ru мы спрашиваем DNS-сервер провайдера. Он, в свою очередь, спрашивает корневой DNS-сервер ( 2 ), тот отдает ему адрес сервера .ru . Потом спрашиваем .ru и тот отдает адрес mail.ru . Спрашиваем main.ru и уже он отдает DNS-серверу провайдера IP-адрес dobro.mail.ru .

То есть каждый DNS-сервер знает только про следующий уровень.

Работает механизм кеширования на разных уровнях DNS-серверов, чтобы каждый раз не дергать корневой сервер и всю последовательность.

  • Адрес IPv4 или адрес IPv6. Смотря что прописано в базе DNS-сервера.
  • Адреса DNS-серверов, обслуживающих данную зону (NS)
  • Адреса почтовых серверов для данного домена (MX)

Пример маршрута между DNS-серверами разного уровня: traceroute ya.ru

В файле /etc/hosts мы можем переопределить адрес DNS любых доменов. Постоянно используется для локальной разработки.

IP не реализует передачу данных без потерь и способен передавать данные только между машинами, но не между программами.

TCP — протокол, обеспечивающий надежную последовательную доставку данных. Фактически, TCP предоставляет интерфейс, похожий на файловый ввод/вывод для сетевых соединений.

  • Надежная доставка (убеждается, что все доставил, а не просто передает)
  • Полнодуплексная передача (и от клиента к серверу и от сервера клиенту)
  • Контроль потока — защита от переполнения
# Порты

TCP порт — это «адрес» сетевого соединения в пределах одного хоста. TCP порты позволяют поддерживать множество открытых соединений на одной машине.

Номер порта — целое число, не больше 65535. Порты ниже 1024 требуют привилегий суперпользователя.

Порты решают задачу передачу данных для конкретной программы, а не просто машине. Каждый порт связан с конкретной программой, ОС про это знает и все данные, которые передаются на этот порт, попадут в эту программу.

Исторически некоторые порты закреплены за определенными службами:

  • 20, 21 — FTP
  • 22 — SSH
  • 25 — SMTP
  • 80 — HTTP
  • 443 — HTTPS

Сокет — это IP-адрес с портом («гнездо», соответствующее адресу и порту). Сокеты могут быть серверные (получатель, который слушает) и клиентские (которые отсылают данные).

Каждый процесс может создать «слушающий» сокет (серверный сокет) и привязать его к какому-нибудь порту операционной системы (в UNIX непривилегированные процессы не могут использовать порты меньше 1024). Слушающий процесс обычно находится в цикле ожидания, то есть просыпается при появлении нового соединения. При этом сохраняется возможность проверить наличие соединений на данный момент, установить тайм-аут для операции и т. д.

# TLS-протокол

TLS (Transport Layer Security, ранее SSL) — криптографический протокол, обеспечивающий безопасную передачу данных между хостами в Internet.

TCP обеспечивает надежную доставку (ничего не потеряется), TLP обеспечивает безопасную доставку (никто не узнает, что передаем).

  • Аутентификация сервера (и клиента)
  • Шифрование и сжатие передаваемой информации
  • Защита от подмены и проверка целостности сообщений

# Итого по установке соединения

Для того, чтобы получить страничку при вводе урла в браузер нам нужно опросить ряд DNS-серверов (или один, если запрос закэширован), установить TCP-соединение (1 RTT

) и часто еще и TLP-соединение (1-2 RTT).

RTT — это время, затраченное на отправку сигнала, плюс время, которое требуется для подтверждения, что сигнал был получен.

# Протокол HTTP

# Назначение

Взаимодействие по HTTP начинается после установки соединения по TCP/TLS.

Hyper Text Transfer Protocol — протокол для передачи гипертекста (HTML).

Многие задачи не решены на уровне TCP и нужен протокол более высокого уровня.

HTTP решает следующие задачи:

  • Передача документов (TCP устанавливает потоковую передачу байт. В нем нельзя узнать, когда документ закончился).
  • Передача мета-информации (mime-type, размер документа)
  • Авторизация
  • Поддержка сессий. HTTP работает по принципу "вопрос-ответ". Поэтому нужен какой-то механизм поддержки состояния. Клиент может получать данные каждый раз с разных серверов. Чтобы рассказать, что клиент "свой" данные передаются в заголовках запросов.
  • Кеширование документов (стили, скрипты, шрифты, картинки и пр.)
  • Согласование содержимого (negotiation)
  • Управление соединением. TCP можно только закрыть, в HTTP можно более гибко управлять: закрыть, оставить.

# HTTP-запрос

Запрос — это текст. Увидеть можно из консоли: curl -v ya.ru :

GET /index.html HTTP/1.1 — строка запроса: метод, урл и версия протокола. GET — метод запроса. Говорим серверу, что мы хотим от него.

Далее идут заголовки вида Ключ: Значение . Например, Host: oggettoweb.ru .

Заголовки могут быть любыми, главное, чтобы они соответствовали спецификации

(не содержали переводов строк и пр.)

После заголовков идет пустая строка. Она отмечает конец заголовков и поле нее может быть тело запроса, если надо.

Запрос — это просто текст, написанный по определенным правилам. В этом легко убедится с помощью утилиты nc .

Создадим файл myget , в котором запишем запрос:

Далее передадим его содержимое в команду nc :

Мы получим документ, который запросили.

Вместо GET можно написать HEAD и получить только заголовки документа без тела. Подходит для проверки наличия документа, часто используется роботами.

# HTTP-ответ

Ответ — текст, который разбирается клиентами.

Клиент и сервер выбирают ту версию HTTP, которая поддерживается обоими. Если клиент работает по HTTP1.1, а сервер понимает только HTTP1.0, то будет использован 1.0.

HTTP/1.1 200 OK — 200 — код ответа. Результат операции. ПО ориентируется на число, текст после него больше для человека и особой технической роли не играет.

Content-Type: text/html нужен браузеру обязательно. Без него он не отобразит документ. Остальные заголовки не так важны.

Длина документа задается как Content-Length: 10894 . Соединение при этом можно оставить открытым: Connection: keep-alive . Иногда просто считывается, пока соединение не будет закрыто: Connection: close .

# Методы HTTP-запросов

  • GET — получить документ.
  • HEAD — получить только заголовки.
  • POST — отправка произвольных данных на сервер.

Не так часто используются, как правило отключены на публичных серверах и используются во внутренней логике работы веб-приложения:

  • PUT — отправка документа на сервер
  • DELETE — удаление документа
  • CONNECT , TRACE , OPTIONS — используются редко
  • COPY , MOVE , MKCOL — WebDAV (расширение протокола HTTP, для управления файлами)

# Коды HTTP-ответов

Quick guide to HTTP Status codes:
1XX: Wait a sec
2XX: There ya go
3XX: Fuck off
4XX: Fuck you
5XX: Fuck

  • 1xx — информационные.
  • 2xx — успешное выполнение:
    • 200 OK — запрос успешно выполнен.
    • 204 No Content — запрос успешно выполнен, но документ пуст.
    • 301 Moved Permanently — документ сменил URL. Документ навсегда перенесен, сервер настроить так, чтобы выдавал 302 и браузер дальше ходит по новому урлу.
    • 302 Found — повторить запрос по другому URL. Документ временно перенесен и кешировать новый урл не надо. Используется для предотвращения повторной отправки форм.
    • 304 Not Modified — документ не изменился, использовать кеш.
    • 400 Bad Request — неправильный синтаксис запроса.
    • 401 Unauthorized — требуется авторизация.
    • 403 Forbidden — нет доступа (неверная авторизация).
    • 404 Not Found — документ не найден.
    • 500 Internal Server Error — неожиданная ошибка сервера (application).
    • 502 Bad Gateway — проксируемый сервер отвечает с ошибкой.
    • 504 Gateway Timeout — проксируемый сервер не отвечает.

    # Заголовки

    С помощью заголовков устанавливаются опции протокола.

    Общие для запросов и ответов. Как правило управляют соединением или содержимым тела запроса:

    • Content-Type — MIME тип документа
    • Content-Length — длина сообщения
    • Content-Encoding — кодирование документа, например gzip-сжатие
    • Transfer-Encoding — формат передачи, например, chunked
    • Connection — управление соединением
    • Upgrade — смена протокола

    Только в запросах:

    • Authorization — авторизация, чаще всего логин/пароль
    • Cookie — передача состояния (сессии) на сервер.
    • Referer — URL предыдущего документа, контекст запроса
    • User-Agent — описание web-клиента, версия браузера
    • If-Modified-Since — условный GET запрос
    • Accept-* — согласование (negotiation) содержимого

    Только в ответах:

    • Location — новый URL документа при перенаправлениях
    • Set-Cookie — установка состояния (сессии) в браузере
    • Last-Modified — дата последнего изменения документа
    • Date — Дата на сервере, для согласования кешей
    • Server — описание web-сервера, название и версия

    Механизм сессии: Юзер авторизуется, после авторизации сервер педает клиенту ключ в Set-Cookie и потом клиент этот ключ передает серверу каждый раз при запросах.

    # Управление соединением в HTTP1.1

    Протокол HTTP/1.0 предполагает закрытие TCP соединения сразу после ответа сервера.

    Протокол HTTP/1.1 предполагает удержание TCP соединения, если не было заголовка Connection: close .

    Соединение должно быть закрыто, если:

    • cервер или клиент использует HTTP младше 1.1
    • cервер или клиент передал заголовок Connection: close
    • по истечении таймаута (обычно небольшой, около 10с)

    Иначе соединение остается открытым для последующих запросов.

    Основная задача такого соединения — загрузить все ресурсы для странички за одно соединение по TCP. Живет оно недолго, порядка 10 секунд. То есть это не полноценное персистентное (постоянное) соединение.

    # Веб-сервер

    Занимается обработкой протокола HTTP (отдачей документов веб-клиентам).

    Веб-сервер — это демон — программа, не связанная с консолью или GUI. Она висит в памяти и обрабатывает данные, которые приходят по сети, через сокеты

    (IP + порт в TCP/IP).

    # Примеры

    Apache — самый распространенный. Написан давно, много переписывался (Apache похоже на Patch).

    Nginx (эндженикс) — разработал Игорь Сысоев

    . Более легковесный, быстрый и надежный. Быстро набирает популярность.

    # Запуск

    Nginx запускается инит-скриптом. Примерно так: /etc/init.d/nginx start . Инит скрипт создается тем, кто выкладывает пакет в пакетный менеджер. Там происходит много всего и нам как пользователям это не интересно.

    При запуске демона он читает файл конфигурации ( nginx.conf ). И подтягивает конфиги всех виртуальных хостов.

    Далее он получает 80-й порт, который нужен для обработки HTTP. Порты ниже 1024 требуют привилегий супер-юзера. Для прослушивания 80-го порта нужно запускать сервер под sudo (с привилегиями супер-пользователя).

    Сервер пишет логи. Куда — это прописано в конфиге сайтов и дефолтном конфиге сервера.

    Далее сервер понижает привилегии, чтобы он работал не от супер-юзера. Он запускает дочерние процессы (воркеры или потоки).

    # Файлы, которые использует веб-сервер

    Как правило в конфиге встречается подключение сторониих файлов:

    При инициализации они тоже становятся частью конфигурации.

    Инит-скрипт: /etc/init.d/nginx [start|stop|restart]

    PID-файл — файл идентификатора процесса: /var/run/nginx.pid . Демоны отключаются от консоли после запуска. Этот файл нужен для идентификации процесса демона, чтобы к нему можно было обратится (остановить, перезапустить и пр.).

    Error-лог: /var/log/nginx/error.log — ошибки сервера. Формат отличается для разных серверов, не формализован.

    Access-лог: /var/log/nginx/access.log — обработка про обработанные HTTP-запросы. Жесткий формат лога, можно обрабатывать программно.

    Логи удобнее задавать для каждого проекта в его же папке.

    # Процессы веб-сервера

    Выделяются 2 вида процессов: Master и Worker.

    Мастер-процесс запускается инит-скриптом под root . Мастер-процесс один. Он читает и проверяет конфиг, открывает логи и сокеты (порты), запускает дочерние процессы (воркеры) и управляет ими. После этого мастер-процесс переходит в режим мониторинга.

    Воркер запускается с пониженными привилегиями (например, юзер может называется www-data или nobody ). Воркеров может быт столько, сколько нужно для работы сервера (зависит от модели сетевых соединений, которые использует сервер). Они занимаются обработкой входящих запросов.

    Бывают дополнительные процессы. Например, кэш-менеджеры, которые следят за очисткой кэша.

    # Цикл работы воркер-процессов

    Воркер-процессы работают в цикле. На рисунке процесс начинается сверху:

    После установки соединения воркер читает HTTP-запрос.

    # Модульная архитектура сервера

    Nginx нужно скомпилировать с поддержкой какого-то нужного модуля. В Apache модули можно подгружать динамически.

    Модуль добавляет директивы в конфиг сервера и регистрирует свои обработчики на этапе цикла работы воркеров.

    # Конфигурация веб-сервера

    Виртуальный хост (virtual host) — секция конфига, отвечающая за обслуживание определенного домена. Почти всегда сервер обрабатывает несколько разных доменов.

    Location — секция конфига, отвечающая за обработку набора урлов. Группа урлов — набор определенного типа документов. Их можно обобщать в этой секции конфига.

    # Приоритет урлов в location

    Следующие типы location расположены в порядке уменьшения приоритета:

    Соответственно, в примере location

    * ^.+\.(jpg|jpeg|gif)$ перебьет location / .

    При одинаковых приоритетах выбирается location , который в конфиге расположен выше. Конфиг — это не программа, которая обрабатывается строка-за-строкой. В итоге конфиг превращается в плоскую структуру директив для доменов и последовательность в ней роли не играет.

    # Отдача статических документов

    Нужно сопоставить урлы из HTTP-запросов с файлами:

    Если задан root , то путь из урла склеится с root :

    Если задан alias , то путь из location подменится алиасом:

    Алиас будет работать только по префиксу. А регуляркой не получится.

    # Атрибуты файлов и процессов

    После того, как сервер понял, какой файл отдавать, он проверяет права доступа на файловой системе. Если нет прав на отдачу, то будет ошибка с кодом 403 .

    У каждого процесса есть свой пользователь и группа.

    ps aux | grep nginx — посмотреть все запущенные процессы nginx.

    У файла (каталога) есть так же пользователь (владелец) и группа. И еще права доступа (read, write, execute).

    ls -la — показать файловую систему с указанием владельцев и уровней доступа.

    Чтобы сервер смог открыть файл, у него должны быть права на чтение файла ( r ) и на исполнение каталога ( x ), где этот файл лежит.

    Права распределяются по тройкам rwxrwxrwx : user, group, everyone.

    Если пользователь процесса совпадает с пользователем (владельцем) файла, то проверяется первая тройка. Иначе проверяется совпадение группы, иначе используется третья тройка.

    # Модели обработки сетевых соединений

    Apache — изначально prefork. Запускает процессы на каждое соединение. Самый старый сервер, классика. Научился работать в режиме worker (комбинированный) и threads. Написан на C.

    Nginx — событийно ориентированный, асинхронный. Написан на C.

    NodeJS — событийно ориентированный, асинхронный, на языке высокого уровня. Относительно медленнее Nginx, но очень легко интегрируемый и расширяемый в контексте приложений на JS.

    Сообщения HTTP

    HTTP сообщения — это обмен данными между сервером и клиентом. Есть два типа сообщений: запросы, отправляемые клиентом, чтобы инициировать реакцию со стороны сервера, и ответы от сервера.

    Сообщения HTTP состоят из текстовой информации в кодировке ASCII, записанной в несколько строк. В HTTP/1.1 и более ранних версиях они пересылались в качестве обычного текста. В HTTP/2 текстовое сообщение разделяется на фреймы, что позволяет выполнить оптимизацию и повысить производительность.

    Веб разработчики не создают текстовые сообщения HTTP самостоятельно — это делает программа, браузер, прокси или веб-сервер. Они обеспечивают создание HTTP сообщений через конфигурационные файлы (для прокси и серверов), APIs (для браузеров) или другие интерфейсы.

    From a user-, script-, or server- generated event, an HTTP/1.x msg is generated, and if HTTP/2 is in use, it is binary framed into an HTTP/2 stream, then sent.

    Механизм бинарного фрагментирования в HTTP/2 разработан так, чтобы не потребовалось вносить изменения в имеющиеся APIs и конфигурационные файлы: он вполне прозрачен для пользователя.

    HTTP запросы и ответы имеют близкую структуру. Они состоят из:

    1. Стартовой строки, описывающей запрос, или статус (успех или сбой). Это всегда одна строка.
    2. Произвольного набора HTTP заголовков, определяющих запрос или описывающих тело сообщения.
    3. Пустой строки, указывающей, что вся мета информация отправлена.
    4. Произвольного тела, содержащего пересылаемые с запросом данные (например, содержимое HTML-формы ) или отправляемый в ответ документ. Наличие тела и его размер определяется стартовой строкой и заголовками HTTP.

    Стартовую строку вместе с заголовками сообщения HTTP называют головой запроса, а его данные — телом.

    Requests and responses share a common structure in HTTP

    Запросы HTTP

    Стартовая строка

    HTTP запросы — это сообщения, отправляемые клиентом, чтобы инициировать реакцию со стороны сервера. Их стартовая строка состоит из трёх элементов:

    1. Метод HTTP, глагол (например, GET , PUT или POST ) или существительное (например, HEAD или OPTIONS ), описывающие требуемое действие. Например, GET указывает, что нужно доставить некоторый ресурс, а POST означает отправку данных на сервер (для создания или модификации ресурса, или генерации возвращаемого документа).
    2. Цель запроса, обычно URL, или абсолютный путь протокола, порт и домен обычно характеризуются контекстом запроса. Формат цели запроса зависит от используемого HTTP-метода. Это может быть
      • Абсолютный путь, за которым следует ‘?’ и строка запроса. Это самая распространённая форма, называемая исходной формой (origin form) . Используется с методами GET , POST , HEAD , и OPTIONS . POST / HTTP 1.1 GET /background.png HTTP/1.0 HEAD /test.html?query=alibaba HTTP/1.1 OPTIONS /anypage.html HTTP/1.0
      • Полный URL — абсолютная форма (absolute form) , обычно используется с GET при подключении к прокси. GET http://developer.mozilla.org/ru/docs/Web/HTTP/Messages HTTP/1.1
      • Компонента URL «authority», состоящая из имени домена и (необязательно) порта (предваряемого символом ‘:’ ), называется authority form. Используется только с методом CONNECT при установке туннеля HTTP. CONNECT developer.mozilla.org:80 HTTP/1.1
      • Форма звёздочки (asterisk form), просто «звёздочка» ( ‘*’ ) используется с методом OPTIONS и представляет сервер. OPTIONS * HTTP/1.1
    3. Версия HTTP, определяющая структуру оставшегося сообщения, указывая, какую версию предполагается использовать для ответа.

    Заголовки

    Заголовки запроса HTTP имеют стандартную для заголовка HTTP структуру: не зависящая от регистра строка, завершаемая ( ‘:’ ) и значение, структура которого определяется заголовком. Весь заголовок, включая значение, представляет собой одну строку, которая может быть довольно длинной.

    Существует множество заголовков запроса. Их можно разделить на несколько групп:

    Example of headers in an HTTP request

    • Основные заголовки (General headers), например, Via (en-US), относящиеся к сообщению в целом
    • Заголовки запроса (Request headers), например, User-Agent , Accept-Type , уточняющие запрос (как, например, Accept-Language ), придающие контекст (как Referer ), или накладывающие ограничения на условия (like If-None ).
    • Заголовки сущности, например Content-Length , относящиеся к телу сообщения. Как легко понять, они отсутствуют, если у запроса нет тела.

    Последней частью запроса является его тело. Оно бывает не у всех запросов: запросы, собирающие (fetching) ресурсы, такие как GET , HEAD , DELETE , или OPTIONS , в нем обычно не нуждаются. Но некоторые запросы отправляют на сервер данные для обновления, как это часто бывает с запросами POST (содержащими данные HTML-форм).

    Тела можно грубо разделить на две категории:

    • Одноресурсные тела (Single-resource bodies), состоящие из одного отдельного файла, определяемого двумя заголовками: Content-Type и Content-Length . ), состоящие из множества частей, каждая из которых содержит свой бит информации. Они обычно связаны с HTML-формами.

    Ответы HTTP

    Строка статуса (Status line)

    Стартовая строка ответа HTTP, называемая строкой статуса, содержит следующую информацию:

    1. Версию протокола, обычно HTTP/1.1 .
    2. Код состояния (status code), показывающая, был ли запрос успешным. Примеры: 200 , 404 или 302
    3. Пояснение (status text). Краткое текстовое описание кода состояния, помогающее пользователю понять сообщение HTTP..

    Пример строки статуса: HTTP/1.1 404 Not Found.

    Заголовки

    Заголовки ответов HTTP имеют ту же структуру, что и все остальные заголовки: не зависящая от регистра строка, завершаемая двоеточием ( ‘:’ ) и значение, структура которого определяется типом заголовка. Весь заголовок, включая значение, представляет собой одну строку.

    Существует множество заголовков ответов. Их можно разделить на несколько групп:

    • Основные заголовки (General headers), например, Via (en-US), относящиеся к сообщению в целом.
    • Заголовки ответа (Response headers), например, Vary и Accept-Ranges , сообщающие дополнительную информацию о сервере, которая не уместилась в строку состояния.
    • Заголовки сущности (Entity headers), например, Content-Length , относящиеся к телу ответа. Отсутствуют, если у ответа нет тела.

    Example of headers in an HTTP response

    Последней частью ответа является его тело. Оно есть не у всех ответов: у ответов с кодом состояния, например, 201 или 204 , оно обычно отсутствует.

    Тела можно разделить на три категории:

    • Одноресурсные тела (Single-resource bodies), состоящие из отдельного файла известной длины, определяемые двумя заголовками: Content-Type и Content-Length .
    • Одноресурсные тела (Single-resource bodies), состоящие из отдельного файла неизвестной длины, разбитого на небольшие части (chunks) с заголовком Transfer-Encoding (en-US), значением которого является chunked . , состоящие из многокомпонентного тела, каждая часть которого содержит свой сегмент информации. Они относительно редки.

    Фреймы HTTP/2

    Сообщения HTTP/1.x имеют несколько недостатков в отношении производительности:

    • Заголовки, в отличие от тел, не сжимаются.
    • Заголовки, которые зачастую практически совпадают у идущих подряд сообщений, приходится передавать по отдельности.
    • Мультиплексность невозможна. Приходится открывать соединение для каждого сообщения, а тёплые (warm) соединения TCP эффективнее холодных (cold).

    HTTP/2 переходит на новый уровень: он делит сообщения HTTP/1.x на фреймы, которые внедряются в поток. Фреймы данных из заголовков отделены друг от друга, что позволяет сжимать заголовки. Несколько потоков можно объединять друг с другом — такой процесс называется мультиплексированием — что позволяет более эффективно использовать TCP-соединения.

    HTTP/2 modify the HTTP message to divide them in frames (part of a single stream), allowing for more optimization.

    Фреймы HTTP сейчас прозрачны для веб-разработчиков. Это дополнительный шаг, который HTTP/2 делает по отношению к сообщениям HTTP/1.1 и лежащему в основе транспортному протоколу. Для реализации фреймов HTTP веб-разработчикам не требуется вносить изменения в имеющиеся APIs; если HTTP/2 доступен и на сервере, и на клиенте, он включается и используется.

    Заключение

    Сообщения HTTP играют ключевую роль в использовании HTTP; они имеют простую структуру и хорошо расширяемы. Механизм фреймов в HTTP/2 добавляет ещё один промежуточный уровень между синтаксисом HTTP/1.x и используемым им транспортным протоколом, не проводя фундаментальных изменений: создаётся надстройка над уже зарекомендовавшими себя методами.

    Что такое HTTP и зачем он нужен

    Рассказываем об одном из самых популярных интернет-протоколов, на котором работает весь современный веб — HTTP.

    Иллюстрация: Оля Ежак для Skillbox Media

    Дмитрий Зверев

    Каждый раз, когда вы включаете компьютер и заходите почитать статьи о программировании, браузер посылает куда-то какие-то запросы. Он делает это беспрерывно, пока вы сидите в интернете. Что это за запросы и зачем они нужны? Давайте разбираться.

    Что такое HTTP

    HTTP означает «протокол передачи гипертекста» (или HyperText Transfer Protocol). Он представляет собой список правил, по которым компьютеры обмениваются данными в интернете. HTTP умеет передавать все возможные форматы файлов — например, видео, аудио, текст. Но при этом состоит только из текста.

    Например, когда вы вписываете в строке браузера www.skillbox.ru, он составляет запрос и отправляет его на сервер, чтобы получить HTML-страницу сайта. Когда сервер обрабатывает запрос, то он отправляет ответ, в котором написано, что всё «ок» и вот вам сайт.

    Протокол HTTP используют ещё с 1992 года. Он очень простой, но при этом довольно функциональный. А ещё HTTP находится на самой вершине модели OSI (на прикладном уровне), где приложения обмениваются друг с другом данными. А работает HTTP с помощью протоколов TCP/IP и использует их, чтобы передавать данные.

    Кроме HTTP в интернете работает ещё протокол HTTPS. Аббревиатура расшифровывается как «защищённый протокол передачи гипертекста» (или HyperText Transfer Protocol Secure). Он нужен для безопасной передачи данных по Сети. Всё происходит по тем же принципам, как и у HTTP, правда, перед отправкой данные дополнительно шифруются, а затем расшифровываются на сервере.

    Например, HTTPS используют во время ввода данных банковской карты или паролей на сайтах — да и в целом большинство современных сайтов используют именно его.

    Из чего состоит HTTP

    HTTP состоит из двух элементов: клиента и сервера. Клиент отправляет запросы и ждёт данные от сервера. А сервер ждёт, пока ему придёт очередной запрос, обрабатывает его и возвращает ответ клиенту.

    Обычно эта связь между клиентом и сервером имеет посредников в виде прокси-серверов. Они нужны для разных операций — например, для безопасности и конфиденциальности, кэширования или распределения нагрузки на серверы.

    Поэтому типичная процедура отправки HTTP-запроса от клиента выглядит так:

    Клиентом может быть любое устройство, через которое пользователь запрашивает данные. Часто в роли клиента выступает веб-браузер, программы для отладки приложений или даже командная строка. Главная особенность клиента — он всегда инициирует запрос.

    Сервер — это устройство, которое обрабатывает запросы клиента. Он может состоять как из одного компьютера, так и из кластера. А ещё несколько виртуальных серверов могут находиться на одной физической машине.

    Прокси-серверы — это второстепенные серверы, которые располагаются между клиентом и главным сервером. Они обрабатывают HTTP-запросы, а также ответы на них. Чаще всего прокси-серверы используют для кэширования и сжатия данных, обхода ограничений и анонимных запросов. И ещё — обычно между клиентом и основным сервером находится один или несколько таких прокси-серверов.

    Как HTTP-протокол работает

    Весь процесс передачи HTTP-запроса можно разбить на пять шагов. Давайте разберём их подробнее.

    Шаг первый — вписываем URL в браузер

    Чтобы отправить HTTP-запрос, нужно использовать URL-адрес — это «унифицированный указатель ресурса» (или Uniform Resource Locator). Он указывает браузеру, что нужно использовать HTTP-протокол, а затем получить файл с этого адреса обратно. Обычно URL-адреса начинаются с http:// или https:// (зависит от версии протокола).

    Например, http://www.skillbox.ru — это URL-адрес. Он представляет собой главную страницу Skillbox. Но также в URL-адресе могут быть и поддомены — http://www.skillbox.ru/media. Теперь мы запросили главную страницу Skillbox Media.

    Шаг второй — браузер находит IP-адрес

    Для пользователей URL-адрес — это набор понятных слов: Skillbox, Yandex, Google. Но для компьютера эти понятные нам слова — набор непонятных символов.

    Поэтому браузер отправляет введённые вами слова в DNS, преобразователь URL-адресов в IP-адреса. DNS расшифровывается как «доменная система имён» (Domain Name System), и его можно представить как огромную таблицу со всеми зарегистрированными именами для сайтов и их IP-адресами.

    Шаг третий — браузер отправляет HTTP-запрос

    DNS возвращает браузеру IP-адрес, с которым тот уже умеет работать. Теперь браузер начинает составлять HTTP-запрос с вложенным в него IP-адресом.

    Сам HTTP-запрос может выглядеть так:

    Здесь четыре элемента: метод — «GET», URI — «/», версия HTTP — «1.1» и адрес хоста — «www.skillbox.ru». Давайте разберём каждый из них подробнее.

    Метод — это действие, которое клиент ждёт от сервера. Например, отправить ему HTML-страницу сайта или скачать документ. Протокол HTTP не ограничивает количество разных методов, но программисты договорились между собой использовать только три основных:

    • GET — чтобы получить данные с сервера. Например, видео с YouTube или мем с Reddit.
    • POST — чтобы отправить данные на сервер. Например, сообщение в Telegram или новый трек в SoundCloud.
    • HEAD — чтобы получить только метаданные об HTML-странице сайта. Это те данные, которые находятся в <head>-теге HTML-файла.

    URI расшифровывается как «унифицированный идентификатор ресурса» (или Uniform Resource Identifier) — это полный адрес сайта в Сети. Он состоит из двух частей: URL и URN. Первое — это адрес хоста. Например, www.skillbox.ru или www.vk.com. Второе — это то, что ставится после URL и символа / — например, для URI www.skillbox.ru/media URN-адресом будет /media. URN ещё можно назвать адресом до конкретного файла на сайте.

    Версия HTTP указывает, какую версию HTTP браузер использует при отправке запроса. Если её не указывать, по умолчанию будет стоять версия 1.1. Она нужна, чтобы сервер вернул HTTP-ответ с той же версией HTTP-протокола и не создал ошибок с чтением у клиента.

    Адрес хоста нужен, чтобы указать, с какого сайта клиент пытается получить данные. Адрес указывают в виде домена, но он сразу же меняется на IP-адрес перед отправкой запроса с помощью DNS.

    Шаг четвёртый — сервер отдаёт HTTP-ответ

    После получения и обработки HTTP-запроса сервер создаёт ответ и отправляет его обратно клиенту. В нём содержатся дополнительная информация (метаданные) и запрашиваемые данные.

    Простой HTTP-ответ выглядит так:

    Здесь три главные части: статус ответа — HTTP/1.1 200 OK, заголовки Content-Type и Content-Length и тело ответа — HTML-код. Рассмотрим их подробнее.

    Статус ответа содержит версию HTTP-протокола, который клиент указал в HTTP-запросе. А после неё идёт код статуса ответа — 200, что означает успешное получение данных. Затем — словесное описание статуса ответа: «ок».

    Всего статусов в спецификации HTTP 1.1 — 40. Вот самые популярные из них:

    • 200 OK — данные успешно получены;
    • 201 Created — значит, что запрос успешный, а данные созданы. Его используют, чтобы подтверждать успех запросов PUT или POST;
    • 300 Moved Permanently — указывает, что URL-адрес изменили навсегда;
    • 400 Bad Request — означает неверно сформированный запрос. Обычно это случается в связке с запросами POST и PUT, когда данные не прошли проверку или представлены в неправильном формате;
    • 401 Unauthorized — нужно выполнить аутентификацию перед тем, как запрашивать доступ к ресурсу;
    • 404 Not Found — значит, что не удалось найти запрашиваемый ресурс;
    • 405 Forbidden — говорит, что указанный метод HTTP не поддерживается для запрашиваемого ресурса;
    • 409 Conflict — произошёл конфликт. Например, когда клиент хочет создать дважды данные с помощью запроса PUT;
    • 500 Internal Server Error — означает ошибку со стороны сервера.

    Заголовки помогают браузеру разобраться с полученными данными и представить их в правильном виде. Например, заголовок Content-Type сообщает, какой формат файла пришёл и какие у него дополнительные параметры, а Content-Length — сколько места в байтах занимает этот файл.

    Тело ответа содержит в себе сам файл. Например, сервер может вернуть код HTML-документа или отправить JPEG-картинку.

    Шаг пятый — браузер отображает веб-страницу

    Как только браузер получил ответ с веб-страницей, он отображает её с помощью внутреннего движка. И на этом весь процесс отправки и получение HTTP-запросов заканчивается, а клиент получает нужные ему данные.

    Ультимативный гайд по HTTP. Структура запроса и ответа

    Привет! Меня зовут Ивасюта Алексей, я техлид команды Bricks в Авито в кластере Architecture. Я решил написать цикл статей об истории и развитии HTTP, рассмотреть каждую из его версий и проблемы, которые они решали и решают сейчас.

    Весь современный веб построен на протоколе HTTP. Каждый сайт использует его для общения клиента с сервером. Между собой сервера тоже часто общаются по этому протоколу. На данный момент существует четыре его версии и все они до сих пор используются. Поэтому статьи будут полезны инженерам любых уровней и специализаций, и помогут систематизировать знания об этой важной технологии.

    Что такое HTTP

    HTTP — это гипертекстовый протокол передачи данных прикладного уровня в сетевой модели OSI. Его представил миру Тим Бернерс-Ли в марте 1991 года. Главная особенность HTTP — представление всех данных в нём в виде простого текста. Через HTTP разные узлы в сети общаются между собой. Модель клиент-серверного взаимодействия классическая: клиент посылает запрос серверу, сервер обрабатывает запрос и возвращает ответ клиенту. Полученный ответ клиент обрабатывает и решает: прекратить взаимодействие или продолжить отправлять запросы.

    Ещё одна особенность: протокол не сохраняет состояние между запросами. Каждый запрос от клиента для сервера — отдельная транзакция. Когда поступают два соседних запроса, сервер не понимает, от одного и того же клиента они поступили, или от разных. Такой подход значительно упрощает построение архитектуры веб-серверов.

    Как правило, передача данных по HTTP осуществляется через открытое TCP/IP-соединение 1 . Серверное программное обеспечение по умолчанию обычно использует TCP-порт 80 для работы веб-сервера, а порт 443 — для HTTPS-соединений.

    HTTPS (HTTP Secure) — это надстройка над протоколом HTTP, которая поддерживает шифрование посредством криптографических протоколов SSL и TLS. Они шифруют отправляемые данные на клиенте и дешифруют их на сервере. Это защищает данные от чтения злоумышленниками, даже если им удастся их перехватить.

    HTTP/0.9

    В 1991 году была опубликована первая версия протокола с названием HTTP/0.9. Эта реализация была проста, как топор. От интернет-ресурса того времени требовалось только загружать запрашиваемую HTML-страницу и HTTP/0.9 справлялся с этой задачей. Обычный запрос к серверу выглядел так:

    В протоколе был определен единственный метод GET и и указывался путь к ресурсу. Так пользователи получали страничку. После этого открытое соединение сразу закрывалось.

    HTTP/1.0

    Годы шли и интернет менялся. Стало понятно, что нужно не только получать странички от сервера, но и отправлять ему данные. В 1996 году вышла версия протокола 1.0.

    Что изменилось:

    В запросе теперь надо было указывать версию протокола. Так сервер мог понимать, как обрабатывать полученные данные.

    В ответе от сервера появился статус завершения обработки запроса.

    К запросу и ответу добавился новый блок с заголовками.

    Добавили поддержку новых методов:

    HEAD запрашивает ресурс так же, как и метод GET, но без тела ответа. Так можно получить только заголовки, без самого ресурса.

    POST добавляет сущность к определённому ресурсу. Часто вызывает изменение состояния или побочные эффекты на сервере. Например, так можно отправить запрос на добавление нового поста в блог.

    Структура запроса

    Простой пример запроса:

    В первой строчке указаны метод запроса — GET , путь к ресурсу — /path и версия протокола — HTTP/1.0 .

    Далее идёт блок заголовков. Заголовки — это пары ключ: значение , каждая из которых записывается с новой строки и разделяется двоеточием. Они передают дополнительные данные и настройки от клиента к серверу и обратно.

    HTTP — это текстовый протокол, поэтому и все данные передаются в виде текста. Заголовки можно отделить друг от друга только переносом строки. Нельзя использовать запятые, точку с запятой, или другие разделители. Всё, что идет после имени заголовка с двоеточием и до переноса строки, будет считаться значением заголовка 2 .

    В примере серверу передали три заголовка:

    Content-Type — стандартный заголовок. Показывает, в каком формате будут передаваться данные в теле запроса или ответа.

    Content-Length — сообщает длину контента в теле запроса в байтах.

    X-Custom-Header — пользовательские заголовки, начинающиеся с X- с произвольными именем. Через них реализуется специфическая логика обработки для конкретного сервера. Если веб-сервер не поддерживает такие заголовки, то он проигнорирует их.

    После блока заголовков идёт тело запроса, в котором передается текст test .

    А так может выглядеть ответ от сервера:

    В первой строке — версия протокола и статус ответа, например, 200 ОК . Далее идут заголовки ответа. После блока заголовков — тело ответа, в котором записан текст OK .

    Статусы ответов

    Клиенту зачастую недостаточно просто отправить запрос на сервер. Во многих случаях надо дождаться ответа и понять, как сервер обработал запрос. Для этого были придуманы статусы ответов. Это трёхзначные числовые коды с небольшими текстовыми обозначениями. Их можно увидеть в терминале или браузере. Сами коды делятся на 5 классов:

    Информационные ответы: коды 100–199

    Успешные ответы: коды 200–299

    Редиректы: коды 300–399

    Клиентские ошибки: коды 400–499

    Серверные ошибки: коды 500–599

    Мы рассмотрим основные коды, которые чаще всего встречаются в реальных задачах. С остальными более подробно можно ознакомиться в реестре кодов состояния HTTP.

    Информационные ответы

    100 Continue — промежуточный ответ. Он указывает, что запрос успешно принят. Клиент может продолжать присылать запросы или проигнорировать этот ответ, если запрос был завершён.

    Этот код ответа доступен с версии HTTP/1.1.

    101 Switching Protocol присылается в ответ на запрос, в котором есть заголовок Upgrade. Это означает, что сервер переключился на протокол, который был указан в заголовке. Такая методика используется, например, для переключения на протокол Websocket.

    102 Processing — запрос получен сервером, но его обработка ещё не завершена.

    Успешные ответы

    200 OK — запрос принят и корректно обработан веб-сервером.

    201 Created — запрос корректно обработан и в результате был создан новый ресурс. Обычно он присылается в ответ на POST запрос.

    Редиректы

    301 Moved Permanently — запрашиваемый ресурс на постоянной основе переехал на новый адрес. Тогда новый путь к ресурсу указывается сервером в заголовке Location ответа.

    Клиент может изменить метод последующего запроса с POST на GET.

    302 Found — указывает, что целевой ресурс временно доступен по другому URl. Адрес перенаправления может быть изменен в любое время, а клиент должен продолжать использовать действующий URI для будущих запросов. Тогда временный путь к ресурсу указывается сервером в заголовке Location ответа.

    Клиент может изменить метод последующего запроса с POST на GET.

    307 Temporary Redirect — имеет то же значение, что и код 302, за исключением того, что клиент не может менять метод последующего запроса.

    308 Permanent Redirect — имеет то же значение, что и код 301, за исключением того, что клиент не может менять метод последующего запроса.

    Клиентские ошибки

    400 Bad Request — запрос от клиента к веб-серверу составлен некорректно. Обычно это происходит, если клиент не передаёт необходимые заголовки или параметры.

    401 Unauthorized — получение запрашиваемого ресурса доступно только аутентифицированным пользователям.

    403 Forbidden — у клиента не хватает прав для получения запрашиваемого ресурса. Например, когда обычный пользователь сайта пытается получить доступ к панели администратора.

    404 Not Found — сервер не смог найти запрашиваемый ресурс.

    405 Method Not Allowed — сервер знает о существовании HTTP-метода, который был указан в запросе, но не поддерживает его. В таком случае сервер должен вернуть список поддерживаемых методов в заголовке Allow ответа.

    Серверные ошибки

    500 Internal Server Error — на сервере произошла непредвиденная ошибка.

    501 Not Implemented — метод запроса не поддерживается сервером и не может быть обработан.

    502 Bad Gateway — сервер, действуя как шлюз или прокси, получил недопустимый ответ от входящего сервера, к которому он обращался при попытке выполнить запрос.

    503 Service Unavailable — сервер не готов обработать запрос (например, из-за технического обслуживания или перегрузки). Обратите внимание, что вместе с этим ответом должна быть отправлена ​​удобная страница с объяснением проблемы. Этот ответ следует использовать для временных условий, а HTTP-заголовок Retry-After по возможности должен содержать расчётное время до восстановления службы.

    504 Gateway Timeout — этот ответ об ошибке выдается, когда сервер действует как шлюз и не может получить ответ за отведенное время.

    505 HTTP Version Not Supported — версия HTTP, используемая в запросе, не поддерживается сервером.

    В HTTP из всего диапазона кодов используется совсем немного. Те коды, которые не используются для задания определенной логики в спецификации, являются неназначенными и могут использоваться веб-серверами для определения своей специфической логики. Это значит, что вы можете, например, придать коду 513 значение «Произошла ошибка обработки видео», или любое другое. Неназначенные коды вы можете посмотреть в реестре кодов состояния HTTP. 3

    Тело запроса и ответа

    Тело запроса опционально и всегда отделяется от заголовков пустой строкой. А как понять, где оно заканчивается? Всё кажется очевидным: где кончается строка, там и заканчивается тело. Однако, два символа переноса строки в HTTP означают конец запроса и отправляют его на сервер. Как быть, если мы хотим передать в теле текст, в котором есть несколько абзацев с разрывами в две строки?

    По логике работы HTTP соединение отправится сразу после второй пустой строки и сервер получит в качестве данных только строку Первая строка . Описанную проблему решает специальный заголовок Content-Length . Он указывает на длину контента в байтах. Обычно клиенты (например, браузеры) автоматически считают длину передаваемых данных и добавляют к запросу заголовок с этим значением. Когда сервер получит запрос, он будет ожидать в качестве контента ровно столько байт, сколько указано в заголовке.

    Однако, этого недостаточно для того, чтобы передать данные на сервер. Поведение зависит от реализации сервера, но для большинства из них необходимо также передать заголовок Content-Type. Он указывает на тип передаваемых данных. В качестве значения для этого заголовка используют MIME-типы. 4

    MIME (Multipurpose Internet Mail Extensions, многоцелевые расширения интернет-почты) — стандарт, который является частью протокола HTTP. Задача MIME — идентифицировать тип содержимого документа по его заголовку. К примеру, текстовый файл имеет тип text/plain , а HTML-файл — text/html .

    Для передачи данных в формате обычного текста надо указать заголовок Content-Type: text/plain , а для JSON — Content-Type: application/json .

    Можно ли передать тело с GET-запросом?

    Популярный вопрос на некоторых собеседованиях: «Можно ли передать тело с GET-запросом?». Правильный ответ — да. Тело запроса не зависит от метода. В стандарте не описана возможность принимать тело запроса у GET-метода, но это и не запрещено. Технически вы можете отправить данные в теле, но скорее всего веб-сервер будет их игнорировать.

    Представим, что на абстрактном сайте есть форма аутентификации пользователя, в которой есть всего два поля: email и пароль.

    Если пользователь ввёл данные и нажал на кнопку «Войти», то данные из полей формы должны попасть на сервер. Самым простым и распространенным форматом передачи таких данных будет MIME application/x-www-form-urlencoded . В нем все поля передаются в одной строке в формате ключ=значение и разделяются знаком & .

    Запрос на отправку данных будет выглядеть так:

    Тут есть небольшая особенность. Как понять, где заканчивается ключ и начинается его значение, если в пароле будет присутствовать знак «=» ?

    В этом случае сервер не сможет понять, как разбить строку на параметры и их значения. На самом деле значения кодируются при помощи механизма url encoding. 5 При использовании этого механизма знак «=» будет преобразован в код %3D .

    Тогда наш запрос приобретёт такой вид:

    Query string

    Данные на сервер можно передавать через тело запроса и через так называемую строку запроса Query String. Это параметры формата ключ=значение, которые располагаются в пути к ресурсу:

    При этом параметры можно передавать прямо от корня домена:

    Query String имеет такой же формат, как и тело запроса с MIME application/x-www-form-urlencoded , только первая пара значений отделяется от адреса вопросительным знаком.

    Некоторые инженеры ошибочно полагают, что Query String являются параметрами GET-запроса и даже называют их GET-параметрами, но на самом деле это не так. Как и тело запроса, Query String не имеет привязки к HTTP-методам и может передаваться с любым типом запросов.

    Обычно параметры Query String используются в GET-запросах, чтобы конкретизировать получаемый ресурс. Например, можно получить на сервере список файлов, имена которых будут начинаться с переданного значения.

    GET-запросы по своей идеологии должны быть идемпотентными. Это значит, что множественный вызов метода с одними и теми же параметрами должен приводить к одному и тому же результату. Например, поисковые боты перемещаются по сайту только по ссылкам и делают только GET-запросы, потому что исходя из семантики они не смогут таким образом изменить данные на сайте и повлиять на его работу.

    На этом я закончу говорить про версию протокола 1.0, структуру ответов и запросов. В следующей статье я расскажу, что такое Cookies, для чего нужен CORS и как это всё работает. А пока напоследок оставлю полезные ссылки, которые упомянул в тексте:

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *