SignalR через перезапись URL всегда возвращается к длинному опросу - PullRequest
0 голосов
/ 21 февраля 2020

У меня есть веб-приложение, которое использует SignalR. Когда я подключаюсь к веб-приложению изнутри нашего брандмауэра, оно работает нормально и устанавливает соединение через WebSockets. Однако при подключении к тому же веб-приложению из-за пределов нашего брандмауэра через сервер с использованием IIS 8.5, ARR 3, перезаписи URL-адресов и в качестве обратного прокси-сервера соединение SignalR всегда возвращается к длительному опросу. На вкладке «Сеть» я вижу в инструментах разработчика, что соединение с SignalR с использованием WebSockets успешно с кодом состояния 101, но по какой-то причине он сразу пытается подключиться с использованием SSE, а затем LongPolling.

Вот мой URL переписать правило (URL закрыт):

<rule name="Test" enabled="true" stopProcessing="false">
    <match url="(.*)" />
    <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
        <add input="{HTTP_HOST}" pattern="^xxx\.xxxxxxxx\.com$" />
        <add input="{CACHE_URL}" pattern="^(.+)://" />
    </conditions>
    <serverVariables>
        <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
        <set name="HTTP_ACCEPT_ENCODING" value="" />
        <set name="HTTP_SEC_WEBSOCKET_EXTENSIONS" value="" />
    </serverVariables>
    <action type="Rewrite" url="{C:1}://xxx.xxxxxxxx.com/{R:1}" />
</rule>

Я добавил в серверную переменную HTTP_SEC_WEBSOCKET_EXTENSIONS, чтобы очистить заголовок ответа, потому что я прочитал, что разрешение сжатия во время перезаписи URL может вызвать проблемы с сообщениями WebSockets. Переменная HTTP_ACCEPT_ENCODING очищает заголовок запроса при входе, а затем у меня есть соответствующее правило вывода для его сброса. Это было необходимо для обработки внутренней ошибки сервера 500, как описано в этом сообщении в блоге .

Здесь приведена соответствующая часть клиентского кода для установления соединения SignalR (это Angular JS приложение с использованием TypeScript):

namespace app.services {
    export class SignalRService {
        private readonly connection: SignalR.Hub.Connection;
        private readonly proxy: SignalR.Hub.Proxy;

        constructor(readonly $rootScope: ng.IRootScopeService,
                    readonly $log: ng.ILogService) {
            this.connection = $.hubConnection('/signalr', { useDefaultPath: false });
            this.proxy = this.connection.createHubProxy('NotificationsHub');
            this.connection
                .start()
                .done(() => this.$rootScope.$apply(() => this.$rootScope.$broadcast('signalRConnected', true)))
                .fail(error => {
                    this.$rootScope.$apply(() => {
                        this.$rootScope.$broadcast('signalRConnected', false);
                        this.$log.error(error);
                    });
                });
        }
    }
}

Наконец, вот некоторые скриншоты с вкладки сети инструментов разработчика. Это показывает, что попытка подключения через WebSockets вернула код состояния 101, который, как я думал, означает успешное рукопожатие, но затем он немедленно переходит к попытке подключения SSE. Dev Tools Connections

Это показывает детали за линией соединения WebSockets: WebSockets Connection

Я совершенно сбит с толку, почему WebSockets не работает через Перезапись URL. Я прочитал несколько статей и постов в Интернете, но я не смог заставить его перестать возвращаться к длинному опросу. Протокол WebSockets был установлен и включен на сервере DMZ, выполняющем перезапись URL. До этого он получал неверный ответ на заголовок ответа Se c -WebSocket-Accept. Я почти смирился с необходимостью использовать Long Polling, но я надеюсь, что кто-то что-то заметит или может дать какой-нибудь совет, чтобы это работало через WebSockets.

...