Socket.io получава съобщения, преди браузърът да премине към нова страница

Имам проблем с това, че Socket.io получава съобщения точно преди навигация в страницата - обикновено когато съобщението е пряк резултат от някакво действие от страна на сървъра, задействано от навигацията.

Това, което виждам в момента, изглежда така:

  1. Socket.io се свързва
  2. Потребителят задейства навигация в страницата (изпраща формуляр, опреснява и т.н.)
  3. Логиката от страна на сървъра изпраща заявка до сървъра socket.io, който незабавно изпраща събитието до все още свързания клиент
  4. Клиентът получава и потвърждава заявката (почти съм сигурен, че има някакво потвърждение на съобщенията, вградени в socket.io, поправете ме, ако греша) и ще покаже известие на потребителя, но след това...
  5. Връзката socket.io се затваря на оригиналната страница
  6. Новата страница се зарежда и показва
  7. Socket.io отваря нова връзка, но няма нови съобщения, защото последното е получено и потвърдено.

Това всъщност не е грешка сама по себе си, тъй като не мисля, че е разумно да очакваме Socket.io да затвори връзката преди да се появи навигация. Въпреки това не съм много сигурен кой е най-добрият начин да се справя с това. В момента държа една връзка отворена за всеки клиент в даден момент и затварям другата, когато се свърже нова. Това обаче не се случва в този случай, тъй като първият се е затворил, преди вторият да се свърже. Мога също така да поддържам списък на всички клиенти, но това също няма да реши този проблем, защото съобщението все още ще бъде получено от първата връзка.

Може ли някой да предложи решение на този проблем, което да гарантира, че потребителят винаги вижда известие за съобщението?


person robbles    schedule 24.08.2012    source източник


Отговори (2)


Socket.io проследява логическите връзки със собствените си идентификатори на сесии. Ако гледате конзолата, когато клиент се свързва, ще видите идентификаторите:

info  - handshake authorized Q9syoIK47JI7dACYpxiA

Важно е да разберете, че тези идентификатори са на страница и напълно отделни от HTTP сесиите. Клиентската библиотека на Socket.io просто съхранява идентификатора на своята сесия в променлива на JavaScript. Следователно при навигация идентификаторът очевидно се губи.

И така, при навигация се случва следното:

  1. Потребителят е на страница, свързана със sio сесия 1.
  2. Започваме навигация към нова страница. На window.onbeforeunload, Socket.io инициира синхронна XHR заявка, за да каже на сървъра, че прекъсва връзката. Ако успее, сесията (1) незабавно се прекратява; в противен случай сесията в крайна сметка ще изтече.
  3. Зарежда се нова страница. Той ще се свърже със сървъра Socket.io и ще му бъде присвоен нов ID на сесията, 2.
  4. Всичко, което изпратите до сесия 1, очевидно няма да бъде доставено, тъй като нашият клиент вече е свързан към сесия 2.

С базовата функционалност на Socket.io е невъзможно да се направи разлика между потребител, който навигира между страници, и нов потребител. И в двата случая потребителят ще се свърже с нова сесия на Socket.io.

Без да знаете точно как работи вашето приложение или какво се опитвате да постигнете, е трудно да дадете окончателна препоръка за решаване на вашия проблем.

Най-вероятно това, което трябва да можете да направите, е да свържете сесия на Socket.io с на потребителя HTTP сесия. Можете да съхранявате известия в опашка в сесията на потребителя и да ги изтривате, когато се покажат. Има два начина да направите това:

  • Тъй като правите пълно зареждане на страницата, можете да изпращате известия на опашка директно със самата страница. Изтрийте опашката, когато сте изобразили успешно.
  • При нова връзка с Socket.io изпратете непрочетени известия през сокета. Дайте на .emit функция за обратно извикване това е потвърждението за доставка, което Socket.io ви предоставя . Когато доставката бъде потвърдена, можете да изтриете опашката за известия от HTTP сесията на потребителя.
person josh3736    schedule 24.08.2012
comment
В момента внедрявам мое собствено управление на сесии на ниво потребител. Знам за различните идентификатори на сесии за всяка връзка и, както споменах по-горе, прекъсвам всички стари връзки, когато новата връзка се удостовери. Изглежда, че вашето предложение с обратното извикване на .emit ще бъде най-лесното за изпълнение, въпреки че съм малко притеснен, че обратното извикване ще бъде извикано преди страницата да се презареди. Възможно ли е това със закъснение? - person robbles; 25.08.2012
comment
Погледнете го по следния начин: ако изпращате известие в резултат на изпращане на формуляр, в момента, в който искате да изпратите известието, старата връзка със сокет вече е изчезнала и няма да има нова връзка, докато не отговорът е изпратен до браузъра. По този начин ви е необходим метод за поставяне на съобщения в опашка слой над Socket.io; потребителската сесия е естественото място за това. - person josh3736; 25.08.2012

Най-простото решение: Използвайте събитието onbeforeunload, за да изключите socket.io.

Проверих с HTTP дебъгер, че това събитие се задейства, преди браузърът да издаде заявката (поне в Chrome), така че ако socket.io е прекъснат тук, той няма да получи никакви съобщения, предназначени за следващата страница.

window.onbeforeunload = function() {
    socket.disconnect();
};

Не съм тествал това в множество браузъри, така че може да не е идеалното решение, но засега изглежда решава проблема.

person robbles    schedule 27.08.2012