Обнаружение изменений на стороне сервера Live (длинный опрос, короткий опрос или веб-сокеты)

Обоснование и исследование

У меня есть сайт, который требует от пользователей входа в систему для просмотра. Пока пользователи вошли в систему, я хотел бы следить за их сеансом пользователя. Под этим я подразумеваю, что хотел бы знать, истек ли срок их пользовательского сеанса, и, следовательно, перенаправить их.

Сеанс каждого пользователя длится 1 час (или что-то другое, на что я его настроил) и сбрасывается, если они посещают другую страницу (как и большинство систем входа).

На данный момент у меня следующий алгоритм:

  1. Пользователь попадает на приватную страницу (выполняется метод javascript с именем isUserAuthorized())
  2. Метод isUserAuthorized() javascript отправляет запрос AJAX на страницу ajax.example.net/authorized.
  3. Эта страница возвращает объект JSON, указывающий текущий статус пользователя, например:

{ authorized: true, timeout: 3600000 }

  1. Затем метод javascript устанавливает тайм-аут для повторного вызова метода в timeout миллисекундах, предполагая, что сеанс завершится к этому времени.
  2. Если сеанс завершился, перенаправьте пользователя, в противном случае вызовите метод через timeout миллисекунд.

Есть две причины, по которым мне не нравится этот текущий метод:

  1. У меня были проблемы с синхронизацией времени между часами клиента и сервера, это странно, но определенно вызывает проблему...
  2. Он оставляет тайм-аут в фоновом режиме веб-страницы, и, поскольку этот сайт очень загружен javascript, я бы предпочел не иметь этого дополнительного тайм-аута, чтобы сайт оставался максимально плавным.

Мой вопрос

Поэтому мой вопрос: может ли кто-нибудь придумать лучший способ добиться этого? Я думал о длинных опросах или веб-сокетах, но я не уверен на 100%, как использовать любой из них, и учебные пособия по веб-сокетам, которые я нашел, были не очень хорошими! Будут ли они на самом деле лучшим решением?

Я мог бы обойти проблемы с синхронизацией времени, но прежде чем я это сделаю, я хочу убедиться, что нет лучших способов добиться этого...

Если это поможет, вот мой текущий код:

// Set the Authorized Timeout
MN.authorizedTimeout = setTimeout(function(){MN.isUserAuthorized});

/**
 * Is User Authorized
 * Checks to see if the current user is authorized and
 * makes sure their session is still active
 */
MN.isUserAuthorized = isUserAuthorized;
function isUserAuthorized(){
    // TEMPORARY
    console.log('authorising');
    // Set the authorized var
    var authorized = false;
    // Clear the current timeout
    clearTimeout(MN.authorizedTimeout);
    // Send request to determine whether the user is authorized
    $.ajax({
        url: "//ajax.example.net/authorized",
        type: "GET",
        dataType: "JSON",
        cache: false,
        async: false,
        success: function(data){
            console.log(data);
            if(data.authorized){
                // If the user is authorized then check again in timeout milliseconds
                MN.authorizedTimeout = setTimeout(MN.isUserAuthorized,data.timeout_milliseconds);
                // Set authorized to true
                authorized = true;
            }else{
                // If the session has expired then proceed to informing the user
                MN.userSessionExpired();
                // Set authorized to false
                authorized = false;
            }
        }
    });
    // Return the session status boolean
    return authorized;
}

person Ben Carey    schedule 13.05.2013    source источник


Ответы (2)


Обновленный ответ:

Тем не менее, я бы посчитал лучшей практикой вычисление онлайн-статуса на стороне сервера. Таким образом, вы можете убедиться, что нет несоответствия со временем. У вас есть только ваше серверное время.

Чтобы получить онлайн-статус, вы можете использовать длительный подход к опросу. Я привел вам пример:

(function checkLoginStatus(){
    $.ajax({ 
      type: 'POST',
      url: 'loginstatus.php',
      data: {userid : 25},
      success: function(data){
        if(data.logged_in !== true){
          //Log the user out
        }
      }, 
      dataType: "json", 
      complete: checkLoginStatus, 
      timeout: 15000 
    });
})();

Это гарантирует, что новый запрос будет сделан только по прошествии 15 секунд и после завершения запроса.

Старый ответ:

Если ваша единственная забота - наблюдать за вошедшими в систему пользователями, вам не нужно проводить опрос. Я бы оставил все это на стороне сервера. Просто добавьте поле «last_active» в таблицу пользователей.

Всякий раз, когда пользователь взаимодействует (посещает другой сайт), обновите временную метку до текущей временной метки.

Чтобы определить, находится ли пользователь в сети, возьмите текущую временную метку и вычтите из нее временную метку «last_active». Если разница больше одного часа, вы знаете, что ваш пользователь неактивен.

Я обычно так справляюсь. Это также более эффективно (в отношении ресурсов), чем с AJAX.

person thpl    schedule 13.05.2013
comment
Спасибо за ваш ответ, но это не совсем то, что я ищу. У меня есть таблица аудита, чтобы узнать, когда пользователь был в последний раз активен. То, что я пытаюсь сделать, это выйти из системы, если срок их сеанса истек. Единственный способ узнать, истек ли срок их сеанса, - это просмотреть базу данных и посмотреть, когда они были в последний раз активны... Поэтому мне нужен какой-то запрос AJAX. - person Ben Carey; 13.05.2013
comment
Спасибо за обновленный ответ. Просто чтобы быть ясным, я обрабатываю все сеансы моих пользователей на стороне сервера. Ничего не нужно передавать на авторизованную страницу, чтобы указать, кто вошел в систему или что-то еще. Эти страницы просто предоставляют объект JSON статуса вошедших в систему пользователей. Это сгенерировано на стороне сервера... Именно несоответствие времени является причиной, по которой я задал этот вопрос, я хотел бы найти лучший способ немедленно узнать, когда истек срок действия сеанса пользователя. Учтите, что пользователь открывает страницу A, а затем открывает другую страницу B на другой вкладке. На странице Б он нажимает кнопку выхода (продолжение) - person Ben Carey; 13.05.2013
comment
После нажатия кнопки выхода он, очевидно, вышел из системы, но страница А этого не отражает. Если он попытается сохранить одну из форм или что-нибудь на странице, он получит сообщение об ошибке. По сути, мне бы хотелось, чтобы система знала, как только сеанс пользователя закончился, это может быть связано со многими причинами, будь то срок его действия или он вышел из системы вручную. Я просто хочу перенаправить пользователя, как только сеанс завершится. Единственный способ узнать, закончился ли сеанс, - это посмотреть на серверную сторону, таким образом, короткий опрос, длинный опрос или веб-сокеты... ??? - person Ben Carey; 13.05.2013

Похоже, что в целом вам нужно что-то на сервере, что будет предупреждать интерфейс в момент истечения сеанса пользователя.

Длинный опрос может сделать это. По сути, у вас будет внутренний контроллер, который принимает соединения и удерживает их, пока не получит сигнал для отправки ответа или время ожидания соединения. Таким образом, ваш интерфейс будет иметь цикл, который в основном отправляет запрос и ждет ответа. Если ответ возвращается пустым, это был тайм-аут, поэтому отправьте новый запрос. Если в ответе есть содержание, время ожидания не истекло, поэтому вы можете принять меры. Это достигает вашей цели, и многие подобные системы построены таким образом. Тем не менее, использование HTTP в обратном порядке — своего рода хак, который не обеспечивает чистого кода.

Веб-сокет — это двунаправленный интерфейс между клиентом и сервером. Вот как будет выглядеть ваш клиентский js.

  function connect(){
    websocket = new WebSocket("wss://yoursite.com:8080");
    //attach event handlers
    websocket.onmessage = onMessage;
  }
  function onMessage(evt){
    // do your thing
  }

Как только вы позвоните connect(), вы можете быть уверены, что onMessage() позаботится о вас, когда серверу потребуется связаться с клиентом. Для меня отправка сообщений с сервера на клиент — это именно то, почему у нас есть веб-сокеты, поэтому они являются правильным инструментом для работы.

person mattexx    schedule 20.05.2013
comment
+1 Большое спасибо за ваш ответ. Из того, что я нашел с веб-сокетами, их не очень просто установить в Windows. Знаете ли вы какие-либо хорошие учебники, или вы могли бы провести меня через них. Большинство моих серверов работают под управлением Linux, но этот конкретный проект работает с базой данных MSSQL, поэтому это должна быть Windows :-( - person Ben Carey; 21.05.2013
comment
Используете ли вы какой-либо веб-фреймворк? Здесь перечислены некоторые решения для Windows: en.wikipedia.org/wiki/Websocket - person mattexx; 21.05.2013
comment
Нет, не боюсь. Я использую свой собственный фреймворк... Что посоветуете? Храповик? В прошлом я провел так много исследований о веб-сокетах, но в Интернете так мало информации о том, как их использовать и как они работают... Приятно наконец найти кого-то, кто знает, о чем они говорят! Спасибо за ваше время до сих пор! :-) - person Ben Carey; 21.05.2013
comment
Я использую Ratchet, но это на сервере LAMP, где я активно использую Symfony в качестве веб-фреймворка. Если у вас нет веб-фреймворка и он вам не нужен, я бы выбрал что-то более легкое. Вы смотрели в node.js? Кажется, это очень популярный выбор. Вот руководство по настройке эхо-сервера в Windows 7: cjihrig.com/blog/websockets-in-node-js-0-8-6-for-windows-7 - person mattexx; 21.05.2013