ログインコンポーネントは、promiseの未定義のオブジェクトに関するエラーメッセージによって削除される前に、簡単に表示されます。
これが約束の定義です:
_ 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
_を使用しており、これを試してみました blog
ログインフォームを表示したままにするために、このエラーを回避する方法はありますか?
更新:私は約束の代わりにオブザーバブルを使用しようとしましたが、問題は同じままでした:
_ 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');
});
_
これはワイルドな推測ですが、おそらくAngularのゾーンとの競合です。これはセキュリティライブラリなので、Angularはコア関数をプロキシに置き換えました。たとえば、NgZone
はwindow.setTimeout
とHTTPメソッドを変更します。
したがって、ゾーンの外でこのコードを実行してみることができます。ここでの唯一の問題は、static関数を使用していることであり、これを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
を使用することです
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
を使用できます。
欠点は、TypeScriptタイプが間違っていることです。