Как поддерживать соединение Channel API, когда Интернет отключен

Я использую API канала Google AppEngine. У меня возникла проблема с повторным запуском потерянного соединения из-за сетевого подключения пользователя. Когда вы теряете подключение к Интернету, канал вызывает onError, но не вызывает onClose. Что касается объекта JavaScript, сокет канала открыт.

Как вы справляетесь с потерей соединения из-за проблем с интернетом? Я думаю о 1) с помощью триггера, чтобы закрыть канал и снова открыть его, когда RPC, не связанный с каналом, где-то в приложении удается в первый раз (что указывает на то, что Интернет снова жив) или 2) использовать таймер, который запускает все время и пингует сервер для определения состояния сети (что было целью введения длительного опроса, чтобы таким образом избежать потребления нежелательных ресурсов). Любые другие идеи были бы замечательными.

Наблюдение. Когда подключение к Интернету отсутствует, onError дважды вызывается с инкрементным интервалом (10 секунд, 20 секунд, 40 секунд). После восстановления подключения к Интернету канал не возобновляет подключение. Он перестает работать без каких-либо признаков того, что он мертв.

Спасибо.


person user_1357    schedule 06.12.2013    source источник


Ответы (1)


Когда вы увидите консоль javascript, предположительно вы увидите «400 Unknown SID Error». Если это так, вот мой обходной путь для этого. Это служебный модуль для AngularJS, но обратите внимание на обратный вызов onerror. Пожалуйста, попробуйте этот обходной путь и дайте мне знать, работает он или нет.

Добавлено: я забыл ответить на ваш главный вопрос, но, на мой взгляд, трудно определить, подключены ли вы к Интернету, если на самом деле не пропинговать «Интернет». Так что, возможно, вы захотите использовать некоторую логику повторных попыток, аналогичную следующему коду, с некоторыми изменениями. В следующем примере я просто повторяю попытку 3 раза, но вы можете сделать это больше с некоторыми откатами. Тем не менее, я думаю, что лучший способ справиться с этим — когда приложение потребляет максимальное количество повторных попыток, вы можете указать пользователю, что приложение потеряло соединение, в идеале показывая кнопку или ссылку для повторного подключения к службе канала.

Также вы можете отслеживать соединение на стороне сервера, см.: https://developers.google.com/appengine/docs/java/channel/#Java_Tracking_client_connections_and_disconnections

app.factory('channelService', ['$http', '$rootScope', '$timeout',
  function($http, $rootScope, $timeout) {
    var service = {};
    var isConnectionAlive = false;
    var callbacks = new Array();
    var retryCount = 0;
    var MAX_RETRY_COUNT = 3;

    service.registerCallback = function(pattern, callback) {
      callbacks.push({pattern: pattern, func: callback});
    };

    service.messageCallback = function(message) {
      for (var i = 0; i < callbacks.length; i++) {
        var callback = callbacks[i];
        if (message.data.match(callback.pattern)) {
          $rootScope.$apply(function() {
            callback.func(message);
          });
        }
      }
    };

    service.channelTokenCallback = function(channelToken) {
      var channel = new goog.appengine.Channel(channelToken);
      service.socket = channel.open();
      isConnectionAlive = false;
      service.socket.onmessage = service.messageCallback;

      service.socket.onerror = function(error) {
        console.log('Detected an error on the channel.');
        console.log('Channel Error: ' + error.description + '.');
        console.log('Http Error Code: ' + error.code);
        isConnectionAlive = false;
        if (error.description == 'Invalid+token.' || error.description == 'Token+timed+out.') {
          console.log('It should be recovered with onclose handler.');
        } else {
          // In this case, we need to manually close the socket.
          // See also: https://code.google.com/p/googleappengine/issues/detail?id=4940
          console.log('Presumably it is "Unknown SID Error". Try closing the socket manually.');
          service.socket.close();
        }
      };

      service.socket.onclose = function() {
        isConnectionAlive = false;
        console.log('Reconnecting to a new channel');
        openNewChannel();
      };

      console.log('A channel was opened successfully. Will check the ping in 20 secs.');
      $timeout(checkConnection, 20000, false);
    };

    function openNewChannel(isRetry) {
      console.log('Retrieving a clientId.');
      if (isRetry) {
        retryCount++;
      } else {
        retryCount = 0;
      }
      $http.get('/rest/channel')
          .success(service.channelTokenCallback)
          .error(function(data, status) {
            console.log('Can not retrieve a clientId');
            if (status != 403 && retryCount <= MAX_RETRY_COUNT) {
              console.log('Retrying to obtain a client id')
              openNewChannel(true);
            }
          })
    }

    function pingCallback() {
      console.log('Got a ping from the server.');
      isConnectionAlive = true;
    }

    function checkConnection() {
      if (isConnectionAlive) {
        console.log('Connection is alive.');
        return;
      }
      if (service.socket == undefined) {
        console.log('will open a new connection in 1 sec');
        $timeout(openNewChannel, 1000, false);
        return;
      }
      // Ping didn't arrive
      // Assuming onclose handler automatically open a new channel.
      console.log('Not receiving a ping, closing the connection');
      service.socket.close();
    }

    service.registerCallback(/P/, pingCallback);
    openNewChannel();

    return service;
  }]);
person Takashi Matsuo    schedule 06.12.2013