Websockets на Tomcat 8 + IIS 8 с ARR 3 не работают
Я искал интернет, пытаясь найти любого, кто может столкнуться с этой проблемой, но придет с пустыми руками. Итак, вот:
У нас есть веб-приложение java (на основе Spring MVC 4). Он находится за Microsoft IIS, выступая в качестве балансировщика нагрузки/обратного прокси-сервера, используя маршрутизацию запросов приложений (ARR) v3.
Этот IIS выполняет балансировку нагрузки с помощью ARR для трех разных сред (все работают с тем же Java-кодом): dev.example.com
, demo.example.com
и qa.example.com
.
Приложение обслуживает уведомления в браузерах пользователей с помощью WebSockets через SockJS и stompjs, и все это хорошо работает, а серверы приложений находятся на Tomcat 7. После обновления среды qa.example.com
до Tomcat 8 соединения WebSocket перестали работать - он возвращается к запросам XHR POST.
Хочу подчеркнуть, что никаких изменений в IIS не было, просто сервер приложений qa
.
Вот пример запроса/ответа из среды dev
(рабочий):
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Cookie: <cookies snipped>
Host: dev.example.com
Origin: https://dev.example.com
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: E7aIek0X6qcO9PAl1n6w4Q==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36
Ответ
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: Upgrade
Date: Thu, 22 Oct 2015 02:19:35 GMT
Expires: 0
Pragma: no-cache
Sec-WebSocket-Accept: dKYK05s4eP87iA20aSo/3ntOrPU=
Server: Microsoft-IIS/8.0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
Upgrade: Websocket
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Powered-By: ARR/3.0
X-XSS-Protection: 1; mode=block
Вот пример запроса/ответа из среды qa
(сломан):
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: no-cache
Connection: Upgrade
Cookie: <cookies snipped>
Host: qa.example.com
Origin: https://qa.example.com
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: jTOIAT0+o35+Qi0ZWh2gyQ==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.71 Safari/537.36
Ответ:
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: Upgrade
Date: Thu, 22 Oct 2015 02:18:30 GMT
Expires: 0
Pragma: no-cache
Sec-WebSocket-Accept: P+fEH8pvxcu3sEoO5fDizjSbwJc=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Server: Microsoft-IIS/8.0
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
Upgrade: Websocket
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-Powered-By: ARR/3.0
X-XSS-Protection: 1; mode=block
Единственное очевидное отличие состоит в том, что ответ qa
включает заголовок Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
, в то время как ответ dev
отсутствует.
Я включил "Отслеживание неудачных запросов" в IIS для отладки ответа 101
, и я вижу, что есть некоторые заголовки, которые переписываются IIS - заголовком Sec-WebSocket-Accept
, а именно.
IIS также показывает, что этот запрос создает ошибку 502.5
. Я посмотрел это и нашел это: https://support.microsoft.com/en-us/kb/943891, в котором говорится, что 502.5
является "сбой WebSocket (ARR)" и что все это говорит. Как ни странно, Chrome Dev Tools показывает, что он отвечает 101, как и предполагалось...
Я пробовал все это с локальным сервером приложений (Tomcat 8 без IIS), и веб-сайты работали нормально. Tomcat 7 + IIS + ARR + WebSockets работает отлично. У Tomcat 8 + IIS + ARR + WebSockets нет.
Моя точная версия Tomcat 8 - 8.0.28, но я получил те же результаты на Tomcat 8.0.26.
Мой следующий шаг - сохранить понижение Tomcat 8 до незначительных версий и посмотреть, что-нибудь изменится. Я обновлю здесь, если что-нибудь обнаружу.
Update
Здесь ответ от моего локального сервера (без IIS):
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Connection: upgrade
Date: Thu, 22 Oct 2015 13:59:23 GMT
Expires: 0
Pragma: no-cache
Sec-WebSocket-Accept: 718HnPxHN8crYYzNGFjQf7w8O+Y=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Server: Apache-Coyote/1.1
Strict-Transport-Security: max-age=31536000 ; includeSubDomains
Upgrade: websocket
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Он очень похож на сломанный запрос qa
, но он отлично работает. Поэтому я думаю, что вещь Sec-WebSocket-Extensions
была красной селедкой. Кроме того, Upgrade: websocket
и Connection: upgrade
являются строчными буквами на моем локальном сервере, тогда как Websocket
и Upgrade
, когда вы ставите IIS спереди.
Sec-WebSocket-Extensions
также имеет конечное пространство в qa
после permessage-deflate;
, но локальное не имеет.
Обновление 2
Все работает отлично в среде qa
в Microsoft Edge (Windows 10). Я не пробовал Internet Explorer 11, но я должен предположить, что он, вероятно, также работает. Firefox и Chrome на OSX не работают.
Обновление 3
Запрос от Tomcat до того, как он будет изменен IIS/ARR:
HTTP/1.1 101 Switching Protocols
Server: Apache-Coyote/1.1
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: luP49lroNK9qTdaNNnSCLXnxAWc=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Date: Tue, 27 Oct 2015 21:10:48 GMT
Ответы
Ответ 1
Я нашел решение, хотя оно не так удовлетворительно, как хотелось бы.
В нашем проекте pom.xml
мы имели spring-core:4.2.5
, но spring-websocket
и spring-messaging
были 4.1.6
. Несоответствие версии явно вызывало некоторые проблемы.
Настройка -Dorg.apache.tomcat.websocket.DISABLE_BUILTIN_EXTENSIONS=true
в параметрах запуска Tomcat, когда версии несовместимы, не повлияли. Установка опции JVM, когда версии того же работали, как ожидалось.
Ответ 101
теперь не содержит permessage-deflate
, и веб-узлы могут подключаться без проблем через IIS. Наше приложение не отправляет много данных через сокеты, поэтому мы были в порядке, делая этот компромисс.
Ответ 2
То же самое касается Tomcat7 и IIS8 с использованием ARR3. Мы не используем библиотеки Spring.
Никакие фреймы не отправляются после того, как установлено соединение с веб-сервером, если включены расширения websocket. Но если мы отключили расширение websocket, все работает отлично.