Неверный заголовок фрагмента тела ответа — ошибка ввода-вывода при запросе GET

Настройка — 2 службы Rest, spring-boot 2.x, встроенный tomcat 8.x

Служба A вызывает службу B с помощью restTemplate в тестовом цикле, выполняющемся 300 раз, на каждом сотом интервале в цикле выдается исключение «Исключение неверного заголовка блока».

Включена отладка (<logger name="org.apache.http" level="DEBUG"/>), ниже приведен анализ:

Первые 99 итераций — заголовки запроса/ответа имеют Connection: keep-alive и body/stream заканчиваются возвратом каретки \r\n

Заголовки запроса

"GET /rest/customers/1000000030 HTTP/1.1[\r][\n]"
"Accept-Language: en-us[\r][\n]"
"Accept: application/json[\r][\n]"
"Content-Type: application/json[\r][\n]"
"Host: localhost:9192[\r][\n]"
"Connection: Keep-Alive[\r][\n]"
"User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_25)[\r][\n]"
"Accept-Encoding: gzip,deflate[\r][\n]"
"[\r][\n]"

Заголовки ответа

"HTTP/1.1 200 [\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"X-XSS-Protection: 1; mode=block[\r][\n]"
"Cache-Control: no-cache, no-store, max-age=0, must-revalidate[\r][\n]"
"Pragma: no-cache[\r][\n]"
"Expires: 0[\r][\n]"
"X-Frame-Options: DENY[\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"Cache-Control: no-cache, no-store, max-age=0, must-revalidate[\r][\n]"
"Pragma: no-cache[\r][\n]"
"Expires: 0[\r][\n]"
"Connection: close[\r][\n]"
"Transfer-Encoding: chunked[\r][\n]"
"Date: Wed, 03 Oct 2018 00:31:53 GMT[\r][\n]"
"Content-Type: application/json;charset=UTF-8[\r][\n]"
"[\r][\n]"
"{"customerNumber":"1000000030"}[\r][\n]"

При 100-м вызове — в заголовках запроса указано Connection: keep-alive, но в заголовке ответа указано Connection: close и body/stream БЕЗ возврата каретки \r\n
http- исходящий-0 ‹‹ "конец потока"
Ошибка ввода/вывода при запросе GET для "http://localhost:9192/rest/customers/1000000030": Неверный заголовок чанка

Заголовки запроса

"GET /rest/customers/1000000030 HTTP/1.1[\r][\n]"
"Accept-Language: en-us[\r][\n]"
"Accept: application/json[\r][\n]"
"Content-Type: application/json[\r][\n]"
"Host: localhost:9192[\r][\n]"
"Connection: Keep-Alive[\r][\n]"
"User-Agent: Apache-HttpClient/4.5.5 (Java/1.8.0_25)[\r][\n]"
"Accept-Encoding: gzip,deflate[\r][\n]"
"[\r][\n]"

Заголовки ответа

"HTTP/1.1 200 [\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"X-XSS-Protection: 1; mode=block[\r][\n]"
"Cache-Control: no-cache, no-store, max-age=0, must-revalidate[\r][\n]"
"Pragma: no-cache[\r][\n]"
"Expires: 0[\r][\n]"
"X-Frame-Options: DENY[\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"X-Content-Type-Options: nosniff[\r][\n]"
"Cache-Control: no-cache, no-store, max-age=0, must-revalidate[\r][\n]"
"Pragma: no-cache[\r][\n]"
"Expires: 0[\r][\n]"
"Connection: close[\r][\n]"
"Transfer-Encoding: chunked[\r][\n]"
"Date: Wed, 03 Oct 2018 00:31:53 GMT[\r][\n]"
"Content-Type: application/json;charset=UTF-8[\r][\n]"
"[\r][\n]"
"{"customerNumber":"1000000030"}" <- MISSING \r\n

а. Почему сервер закрывает соединение после 100 вызовов?

Похоже, это причина - Tomcat 8 с соединителями NIO по умолчанию:

  • Максимальное количество подключений, которые может обрабатывать каждый сервер, составляет maxConnections = 10000.
  • Время ожидания каждого соединения connectionTimeout = 60 секунд
  • Максимальное количество потоков определяет в каждом соединении, сколько одновременных запросов может быть обработано maxThreads = 200
  • Минимум всегда доступных запасных потоков (не соединений) = minSpareThreads = 10
  • Максимальное количество запросов поддержания активности в соединении maxKeepAliveRequests = 100 (похоже, это закрывает соединение и не отправляет возврат каретки как часть тела ответа, генерирующего исключение ввода-вывода чтения буфера)

б. При закрытии соединения, почему сервер не отправляет завершение или возврат каретки? Это проблема Spring или tomact?

в. Как или какие настройки нужно изменить, чтобы этого избежать? maxKeepAliveRequests не отображается в свойствах приложения Spring, единственный способ переопределить — реализовать контейнер клиента, реализующий WebServerFactoryCustomizer, а затем вручную переопределить.

Пожалуйста, сообщите, если это ошибка при закрытии соединения на сервере?


person Rajanish    schedule 03.10.2018    source источник
comment
Привет, вы нашли решение? Кажется, у меня такая же проблема с Spring Boot 2.1.4.   -  person fabballe    schedule 11.10.2019


Ответы (1)


Я столкнулся с этой проблемой при использовании функции обмена RestTemplate, я просто фильтрую заголовок Connection, после чего ошибка исчезает.

person i_love_cs    schedule 17.02.2020