我的登录组件会在被有关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
是否有办法解决此错误,以便显示我的登录表单?
更新:我尝试使用observable而不是promise,但问题仍然存在:
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');
});
答案 0 :(得分:3)
这是一个疯狂的猜测,但也许它与Angular的区域发生冲突。由于这是一个安全库,它可能不喜欢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
答案 1 :(得分:0)
如果您删除了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
。
缺点是打字稿类型会错误。
答案 2 :(得分:0)
我们观察到了一个关于 promise 对象 undefined 的类似错误。情况是我们的本地应用程序在本地 keycloak 独立服务器上运行良好,但是当本地应用程序尝试连接托管在 ABC 服务器上的 keycloak 服务器时遇到此错误(此处使用 ABC 作为参考以提供任意名称)。
当我们在 ABC 服务器上托管应用程序和 keycloak 服务器时,这个问题得到了解决。
看起来在不同的机器上有一些时间同步问题,因为没有返回 promise 对象。