使用Angular关闭浏览器窗口/选项卡时执行异步服务获取

时间:2019-05-13 13:54:05

标签: angular onbeforeunload onunload sendbeacon

当用户试图离开我的页面时,我目前正在尝试使Angular应用程序进行API服务调用。关闭标签页/窗口,或输入外部URL。

我已尝试实现我在此处介绍的关于stackoverflow问题的几种不同方式,但是似乎没有一种方法具有预期的效果。有人提到在Chrome上onbeforeunload中已经或正在弃用同步ajax请求。其他人建议使用似乎遭受同样命运的XMLHttpRequests。 我尝试使用 @HostListener('window:onbeforeunload', ['$event'])和HTML (window:beforeunload)="doBeforeUnload($event)"中的等效语言,但是所有人都拒绝合作。我可以显示console.logs,但是API永远不会收到任何注销用户的调用。 我还使用了navigator.sendBeacon,尽管其功能返回true,表示该作业已发送到浏览器队列,但没有实现。

当前,注销功能是这样的:

userLogout(): Observable<any> {
    return this.apiService.get('/Account/Logout/');
  }

这又是一个通用的http get函数:

get<T>(url: string, options?: { params: HttpParams }): Observable<any> {
    return this.httpRequest<T>('get', url, null, options ? options.params : null);
  }

使用HttpInterceptor添加完整的URL。注销功能本身正在工作,因为它在菜单选项中使用,手动使用时可以按预期工作。因此功能应该不是问题。

我要做的就是以同步或异步方式调用userLogout函数,并通知后端用户已离开。

2 个答案:

答案 0 :(得分:1)

对于我来说,async/await非常适合在关闭浏览器标签/更改标签网址的同时拨打http。

@HostListener('window:beforeunload', ['$event']) 
async beforeunloadHandler(event) {
    await triggerSyncLogout();
}
async triggerSyncLogout(){
    let url = 'www.sample.com';
    let reqHeaders = new HttpHeaders().append('Authorization', token).append('Accept', 'application/json');
    const options = {
        headers: reqHeaders,
        withCredentials: true,
        observe: 'response' as 'response'
    }
    return await this.http.get<any>(url, options).toPromise();
}

答案 1 :(得分:0)

经过一番修补,我最终基于answer得到了一个解决方案,尽管由于某种原因,它对我的​​初次尝试没有用。

我在组件中添加了以下HostBinding:

@HostListener('window:beforeunload', ['$event']) beforeunloadHandler(event) {
    this.pageClosed();
}

其中调用了一个简单的函数,该函数将使用身份验证服务注销方法。

pageClosed() {
    this.authenticationService.userLogoutSync();
}

我必须创建一个单独的注销功能,以便它可以是同步的。还必须添加标题以进行后端授权,因为我的Http拦截器无法捕获XMLHttpRequest并将其自身添加。

const xhr = new XMLHttpRequest();
    xhr.open('GET', environment.backend + '/Account/Logout/', false);
    xhr.setRequestHeader('Authorization', 'Bearer ' + this.jwtService.getAccessToken());
    xhr.send();
}