如何在IONIC 3的Http Interceptor中使用NavControl并实现401跳转登录
为什么不能直接在拦截器中注入NavController?
因为Ionic 3基于Angular 4,拦截器属于HTTP模块的注入上下文,而NavController依赖于页面层级的注入器,直接注入会触发循环依赖错误。我们需要通过间接方式获取导航实例,或者使用事件总线解耦。
方法一:通过Ionic App服务获取NavController实例
这是最直接的方式,利用App服务获取根导航控制器来实现页面跳转。
步骤1:切换到HttpClientModule
Angular 4的拦截器仅支持HttpClient,因此需要在app.module.ts中替换原有的HttpModule:
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; @NgModule({ imports: [ // ...其他模块 HttpClientModule // 替换 HttpModule ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true // 允许多个拦截器 } ] }) export class AppModule {}
步骤2:创建Auth拦截器
新建auth.interceptor.ts,实现HttpInterceptor接口,通过App服务获取导航实例:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { App } from 'ionic-angular'; import { LoginPage } from '../pages/login/login'; // 导入你的登录页 @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private app: App) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> { // 给请求添加Authorization头(如果有token的话) const authReq = request.clone({ setHeaders: { Authorization: `Bearer ${localStorage.getItem('auth_token')}` } }); // 处理响应和错误 return next.handle(authReq).catch((error: HttpErrorResponse) => { if (error.status === 401) { // 清除本地无效token localStorage.removeItem('auth_token'); // 获取根导航控制器并跳转登录页 const rootNav = this.app.getRootNav(); rootNav.setRoot(LoginPage); } return Observable.throw(error); }); } }
方法二:使用Ionic Events事件总线解耦
这种方式将导航逻辑从拦截器中分离,避免直接依赖导航服务,解耦性更好。
步骤1:在拦截器中触发401事件
修改拦截器,注入Events服务并发布事件:
import { Injectable } from '@angular/core'; import { HttpInterceptor, HttpRequest, HttpHandler, HttpErrorResponse } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import { Events } from 'ionic-angular'; @Injectable() export class AuthInterceptor implements HttpInterceptor { constructor(private events: Events) {} intercept(request: HttpRequest<any>, next: HttpHandler): Observable<any> { const authReq = request.clone({ setHeaders: { Authorization: `Bearer ${localStorage.getItem('auth_token')}` } }); return next.handle(authReq).catch((error: HttpErrorResponse) => { if (error.status === 401) { localStorage.removeItem('auth_token'); // 发布401未授权事件 this.events.publish('auth:unauthorized'); } return Observable.throw(error); }); } }
步骤2:在AppComponent中监听事件并跳转
在app.component.ts中监听事件,调用NavController跳转登录页:
import { Component } from '@angular/core'; import { Platform, Events, NavController } from 'ionic-angular'; import { LoginPage } from '../pages/login/login'; import { HomePage } from '../pages/home/home'; @Component({ templateUrl: 'app.html' }) export class MyApp { rootPage: any = localStorage.getItem('auth_token') ? HomePage : LoginPage; constructor( platform: Platform, private events: Events, private navCtrl: NavController ) { platform.ready().then(() => { // 监听未授权事件 this.events.subscribe('auth:unauthorized', () => { this.navCtrl.setRoot(LoginPage); }); }); } }
注意事项
- 确保登录页已经在
app.module.ts的entryComponents中声明,否则Ionic无法加载该页面。 - 使用
setRoot而非push跳转登录页,避免用户通过返回按钮回到之前的未授权页面。 - 如果你的项目仍然使用旧的
Http模块而非HttpClient,需要自定义拦截器(继承Http类),但推荐升级到HttpClient以利用官方的拦截器特性。
内容的提问来源于stack exchange,提问作者user5035258
相关产品推荐
相关产品推荐

