Версия HTTP для команды CURL на сервере и образе Docker

Вопрос или проблема

Когда я выполняю вызов CURL curl https://example.com из docker-контейнера, я получаю ошибку curl: (92) HTTP/2 stream 0 was not closed cleanly: HTTP_1_1_REQUIRED (err 13). Но когда я запускаю ту же команду с хост-сервера (RHEL), на котором работает docker-контейнер, это работает нормально.

Итак, я добавил –http1.1 к команде в docker-контейнере, и тогда всё работает хорошо. Но когда я запускаю ту же команду с –http1.1 на хост-сервере, я получаю ошибку curl: option --http1.1: is unknown.

  1. Как curl определяет версию http во время вызова? Есть ли какая-либо настройка, которую мы можем определить, чтобы использовать конкретную версию по умолчанию?
  2. Почему –http1.1 не работает на сервере, но работает в docker-контейнере?

Версия Curl на сервере – 7.29.0. Версия Curl в docker-контейнере – 7.64.0

Кратко: Исправьте ваш веб-сервер.

Длинная история

Ваш HTTP-сервер должен делать что-то “неправильно”! curl не попытается установить соединение HTTP/2, если сервер не сообщит, что он может это сделать.

Таким образом, ответы на вопросы:

Как curl определяет версию http во время вызова?

Он слушает, что сервер заявляет о поддержке.

Есть ли какая-либо настройка, которую мы можем определить, чтобы использовать конкретную версию по умолчанию?

Да, это встроено в HTTP-протокол (первая строка ответа); на самом деле, с учетом того, что вы используете TLS (https://…), это должно быть уже четко определено клиентом с использованием идентификатора протокола h2 в TLS/ALPN, и сервер ответит, что он поддерживает протокол h2, т.е. он соглашается, что действительно может говорить HTTP/2.

В противном случае curl не будет использовать HTTP/2.

Вы можете сами проверить неправильное поведение вашего HTTP-сервера!

$ # https://stackoverflow.com поддерживает HTTP/2
$ curl --verbose --output /dev/null https://stackoverflow.com
…
* Соединение с stackexchange.com (151.101.65.69) порт 443 (#0)
* ALPN: предлагает h2
* ALPN: предлагает http/1.1
…
* SSL-соединение с использованием TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN: сервер принял h2
…
* Используется HTTP2, сервер поддерживает мультиплексирование
…
> GET / HTTP/2

Таким образом, здесь вы можете увидеть, что curl предлагает h2 как идентификатор протокола серверу, и сервер фактически должен принять это, прежде чем curl использует HTTP/2.

Сравните это с тем, что делает устаревший веб-сервер, и как curl реагирует:

$ # https://www.gnu.org поддерживает только HTTP/1.1 в 2023.
$ curl --verbose --output /dev/null https://www.gnu.org/software/grub/manual/grub/html_node/normal.html
* Соединение с www.gnu.org (2001:470:142:5::116) порт 443 (#0)
* ALPN: предлагает h2
* ALPN: предлагает http/1.1
…
* SSL-соединение с использованием TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN: сервер принял http/1.1
…
> GET /software/grub/manual/grub/html_node/normal.html HTTP/1.1

Таким образом, ваш веб-сервер должен говорить curl при установлении TLS-соединения, что он поддерживает HTTP/2 (сигнализируя о поддержке h2), но при этом фактически не поддерживать его.

Почему –http1.1 не работает на сервере, но работает в docker-контейнере?

Ваш curl на хост-сервере очень старый; эта опция была добавлена в версию curl 7.33.0, что было почти 10 лет назад.

Ответ или решение

Версия HTTP для команды cURL на сервере и в образе Docker

При работе с командами cURL возникает необходимость понять, как происходит выбор версии HTTP, а также почему возникают различия в поведении cURL на хост-сервере и внутри контейнера Docker.

Как cURL выбирает версию HTTP?

При выполнении запроса с помощью cURL клиент устанавливает соединение с сервером и предлагает ему версии протоколов, которые он поддерживает. Это происходит через механизм ALPN (Application-Layer Protocol Negotiation). Именно сервер в ответ на запрос клиента подтверждает, какие версии протокола он поддерживает.

Если сервер поддерживает HTTP/2, он должен ответить, подтвердив использование протокола h2. Если сервер не поддерживает HTTP/2 или не настроен должным образом, cURL автоматически переключится на HTTP/1.1.

Важно: Если вы используете HTTPS, как в вашем случае с https://example.com, это будет происходить в рамках первого этапа установки TLS-соединения. Посредством ALPN клиент и сервер устанавливают совместимую версию протокола.

Установка используемой версии по умолчанию

На данный момент нет прямого встроенного метода для установки версии HTTP по умолчанию в cURL. Однако, вы можете управлять версией HTTP, явно указывая её в команде. В вашем случае, добавление флага --http1.1 решило проблему в контейнере Docker, гарантируя использование HTTP/1.1.

Для проверки поддержки протоколов сервера в cURL можно использовать флаг --verbose, который поможет увидеть, какую версию HTTP использует сервер.

curl --verbose --output /dev/null https://example.com

Почему --http1.1 работает на контейнере, но не на сервере?

Причина, по которой команда с флагом --http1.1 работает в Docker-контейнере, но не на хост-сервере, заключается в различиях в версиях cURL, установленных на каждом из них. В вашем случае:

  • Хост-сервер: cURL версии 7.29.0
  • Контейнер Docker: cURL версии 7.64.0

Флаг --http1.1 был добавлен в cURL начиная с версии 7.33.0. Таким образом, так как ваша версия cURL (7.29.0) на хост-сервере старая, она не распознает этот параметр и выдаст ошибку "Option –http1.1: is unknown".

Рекомендации для решения проблемы

  1. Обновление cURL на хост-сервере: Рекомендуется обновить cURL на вашем хост-сервере до более поздней версии, которая поддерживает новые опции и улучшения. Это может помочь избежать подобных проблем в будущем и обеспечить лучшую функциональность и безопасность.

  2. Проверка конфигурации сервера: Убедитесь, что ваш веб-сервер поддерживает HTTP/2 и корректно настроен для его использования. Возможно, потребуется обновить ваши серверные настройки или программное обеспечение.

  3. Использование контейнеров: Если обновление хост-сервера невозможно, вы также можете рассмотреть использование контейнеров для разработки, что позволяет работа с более современными версиями программного обеспечения без необходимости модифицировать хост-окружение.

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

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

Капча загружается...