Проглоченное сообщение: Ошибка: Uncaught (в обещании): [объект Undefined] - PullRequest
0 голосов
/ 24 апреля 2018

Мой компонент входа в систему кратко отображается перед удалением сообщением об ошибке о неопределенном объекте в обещании.

Вот определение обещания:

  static init(): Promise<any> {
    KeycloakClientService.auth.loggedIn = false;
    return new Promise((resolve, reject) => {
      const keycloakConfig = {
      url: environment.KEYCLOAK_URL,
      realm: environment.KEYCLOAK_REALM,
      clientId: environment.KEYCLOAK_CLIENTID,
      'ssl-required': 'external',
      'public-client': true
      };
      const keycloakAuth: any = new Keycloak(keycloakConfig);

      keycloakAuth.init({onLoad: 'check-sso'})
        .success(() => {
          KeycloakClientService.auth.loggedIn = true;
          KeycloakClientService.auth.authz = keycloakAuth;
          KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
          + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
          + document.baseURI;
          console.log('=======>> The keycloak client has been initiated successfully');
          resolve('Succeeded in initiating the keycloak client');
        })
        .error(() => {
          reject('Failed to initiate the keycloak client');
        });
    });
  }

Вызывается:

KeycloakClientService.init()
  .then(
    () => {
      console.log('The keycloak client has been initialized');
    }
  )
  .catch(
    (error) => {
      console.log(error);
      window.location.reload();
    }
  );

Консоль показывает оба сообщения:

The keycloak client has been initiated successfully
The keycloak client has been initialized

Я использую Angular 6.0.4 и попробовал следовать этому блогу

Есть ли способ обойти эту ошибку, чтобы отображалась форма входа?

ОБНОВЛЕНИЕ: я попытался использовать наблюдаемое вместо обещания, но проблема осталась прежней:

  public init(): Observable<any> {
    KeycloakClientService.auth.loggedIn = false;
    return new Observable((observer) => {
      const keycloakConfig = {
        'url': environment.KEYCLOAK_URL,
        'realm': environment.KEYCLOAK_REALM,
        'clientId': environment.KEYCLOAK_CLIENTID,
        'ssl-required': 'external',
        'public-client': true
      };
      const keycloakAuth: any = new Keycloak(keycloakConfig);

      keycloakAuth.init({ 'onLoad': 'check-sso' })
        .success(() => {
          KeycloakClientService.auth.loggedIn = true;
          KeycloakClientService.auth.authz = keycloakAuth;
          KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
            + document.baseURI;
          console.log('The keycloak auth has been initialized');
          observer.next('Succeeded in initiating the keycloak client');
          observer.complete();
        })
        .error(() => {
          console.log('The keycloak client could not be initiated');
          observer.error('Failed to initiate the keycloak client');
        });
    });
  }

Весь исходный код доступен на GitHub

ОБНОВЛЕНИЕ: Следуя ответу ниже, я также попытался использовать ключевые слова then() и catch(), но ошибка осталась прежней:

keycloakAuth.init({ 'onLoad': 'check-sso' })
        .then(() => {
          KeycloakClientService.auth.loggedIn = true;
          KeycloakClientService.auth.authz = keycloakAuth;
          KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
            + document.baseURI;
          console.log('The keycloak auth has been initialized');
          observer.next('Succeeded in initiating the keycloak client');
          observer.complete();
        })
        .catch(() => {
          console.log('The keycloak client could not be initiated');
          observer.error('Failed to initiate the keycloak client');
        });

Ответы [ 2 ]

0 голосов
/ 31 июля 2018

Если вы удалите блок success, где вы используете свою логику в пределах success?

Я прочитал часть их исходного кода, думаю, именно поэтому success вызывает проблему:

В keycloak.js есть функция createNativePromise():

function createNativePromise() {
var p = {
    setSuccess: function(result) {
        p.success = true;
        p.resolve(result);
    },

    setError: function(result) {
        p.success = false;
        p.reject(result);
    }
};
p.promise = new Promise(function(resolve, reject) {
    p.resolve = resolve;
    p.reject = reject;
});
p.promise.success = function(callback) {
    p.promise.then(callback);
    return p.promise;
}
p.promise.error = function(callback) {
    p.promise.catch(callback);
    return p.promise;
}
return p;
}

И он используется таким образом (упрощенный код):

function refreshToken() {
    var promise = createNativePromise();
    ...
    if (refreshTokenFailed) {
        promise.setError(true);
    }
    ...

    return promise.promise;
}

Проблема в том, promise.setError() вызывает promise.reject(result), поэтому обещание отклонено, оно ожидает catch.

Но внутри promise.success есть promise.promise.then(callback);, и никто не поймал это обещание.

Вот почему вы получаете Uncaught (in promise): [object Undefined], а в моем случае я всегда получаю Uncaught (in promise): true.

Решение:

Обратите внимание, что promise.promise является действительным Promise, поэтому мы можем использовать then и catch вместо success и error.

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

0 голосов
/ 07 июня 2018

Это дикое предположение, но, возможно, это конфликт с зонами Ангулара.Поскольку это библиотека безопасности, возможно, ей не понравится, что Angular заменил основные функции на прокси.Например, NgZone изменяет window.setTimeout и методы HTTP.

Так что вы можете попробовать запустить этот код за пределами зон.Единственная проблема здесь заключается в том, что вы используете статическую функцию, и вам придется сделать эту услугу инъекционной, чтобы вы могли получить доступ к NgZone

@Injectable()
export class KeycloakClientService {
    public constructor(private zone: NgZone) {
    }

    public init(): Promise<any> {
        KeycloakClientService.auth.loggedIn = false;
        return new Promise((resolve, reject) => {
            this.zone.runOutsideAngular(() => {
                const keycloakConfig = {
                     url: environment.KEYCLOAK_URL,
                     realm: environment.KEYCLOAK_REALM,
                     clientId: environment.KEYCLOAK_CLIENTID,
                     'ssl-required': 'external',
                     'public-client': true
                };

                const keycloakAuth: any = new Keycloak(keycloakConfig);

                keycloakAuth.init({onLoad: 'check-sso'})
                    .success(() => {
                        KeycloakClientService.auth.loggedIn = true;
                        KeycloakClientService.auth.authz = keycloakAuth;
                        KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
                            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
                            + document.baseURI;
                        console.log('=======>> The keycloak client has been initiated successfully');
                        resolve('Succeeded in initiating the keycloak client');
                    })
                    .error(() => {
                        reject('Failed to initiate the keycloak client');
                    });
            });
        }
    }
}

Изменение здесьиспользовать zone.runOutsideAngular

...