问题
Angular工程,当用户一段时间没有操作,后端会让token过期,这时应该返回登录界面。
实现原理
通过Http拦截器来实现这个功能。
让后端API在token过期后返回一个固定的状态,本例是response.body.code === ‘00191’。前端拦截Http调用,检查response,如果发现token过期,就发射一个login事件(通过事件与AppComponent#createLoginPage解耦),通过setTimeout延迟发射是为了保证这个http请求的回调函数得到调用之后再调整到登录界面。如果浏览器的事件处理本身就是异步的(事件驱动的机制应该如此),那么setTimeout就是多余的,放在这里也没有坏处。
DynamicCreateService见我的另一篇博客:angular动态创建组件的服务代码
本例也演示了如何在每个请求上面加上头部Authorization,向后端API发送用户token。
import { Injectable } from '@angular/core';
import {
HttpInterceptor,
HttpRequest,
HttpResponse,
HttpHandler,
HttpEvent,
HttpErrorResponse
} from '@angular/common/http';
import { Subscription } from 'rxjs';
import { tap } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
@Injectable()
export class HttpConfigInterceptor implements HttpInterceptor {
constructor() { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token: string = sessionStorage.getItem('userToken');
if (token) {
request = request.clone({ headers: request.headers.set('Authorization', 'Bearer' + token) });
return next.handle(request).pipe(
tap((event: HttpEvent<any>) => {
if (event instanceof HttpResponse) {
if (event.body.code === '00191') {
sessionStorage.clear();
// go to log in page
setTimeout(() => {
const event2 = new CustomEvent('login', { detail: {} });
window.dispatchEvent(event2);
}, 0);
}
}
}));
}
return next.handle(request);
}
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AppComponent implements OnInit, AfterViewInit {
@ViewChild('viewContainer', { read: ViewContainerRef }) container: ViewContainerRef;
componentRef: ComponentRef<any>;
constructor(
private dcs: DynamicCreateService,
private http: HttpClient,
// ...
) {
}
ngOnInit(): void {
window.addEventListener('resize', this.onWindowResize.bind(this));
window.addEventListener('login', () => {
this.createLoginPage();
});
}
ngAfterViewInit(): void {
if (sessionStorage.getItem('userToken')) {
this.createHomePage();
} else {
this.createLoginPage();
}
document.oncontextmenu = () => false;
}
createLoginPage() {
this.componentRef = this.dcs.createComponent(this.container, LoginComponent);
(this.componentRef.instance as LoginComponent).login.subscribe(() => this.createHomePage());
}
// ...
};