我正在使用Angular 2.1.2。
我有一个身份验证令牌(使用angular2-jwt),如果它过期,我的webApi调用将失败并显示401错误。我正在寻找一种解决方案,用户不会丢失任何输入数据。
我可以抓住这个401并用登录打开一个模态。然后用户登录,模态消失,他们看到他们的输入屏幕。但是,失败的请求显示错误,因此我需要重新处理请求。如果是路由器,则导航初始数据尚未加载。
我可以重新加载页面,但如果我router.navigate到同一页面,它似乎并没有真正重新加载页面。我不想在单页面应用上进行整页重新加载。有没有办法强制router.navigate运行,即使它是当前页面?
重新导航仍然是一个问题,因为我会丢失任何未保存的新输入数据。
理想情况下,请求只会“暂停”,直到用户从模式登录。我还没有找到实现这个目标的方法。
有什么想法吗? 有最好的做法吗?
答案 0 :(得分:5)
通常我会自己提供HttpService
而不是直接使用Http
。因此,根据您的要求,我可以提供自己的get()
方法来在发送任何真实HTTP请求之前对身份验证进行链接。
这是服务:
@Injectable()
class HttpService {
constructor(private http: Http, private auth: Authentication) {}
public get(url: string): Observable<Response> {
return this.auth.authenticate().flatMap(authenticated => {
if (authenticated) {
return this.http.get(url);
}
else {
return Observable.throw('Unable to re-authenticate');
}
});
}
}
以下是调用服务的组件:
@Component({
selector: 'my-app',
template: `<h1>Hello {{name}}</h1>
<button (click)="doSomething()">Do Something</button>
<div [hidden]="!auth.showModal">
<p>Do you confirm to log in?</p>
<button (click)="yes()">Yes</button><button (click)="no()">No</button>
</div>
`,
})
export class AppComponent {
name = 'Angular';
constructor(private httpSvc: HttpService, public auth: Authentication) {}
ngOnInit() {
}
doSomething() {
let a = this.httpSvc.get('hello.json').subscribe(() => {
alert('Data retrieved!');
}, err => {
alert(err);
});
}
yes() {
this.auth.confirm.emit(true);
}
no() {
this.auth.confirm.emit(false);
}
}
通过链接observable,Authentication
服务确定是否中断正常流程以显示模态(虽然目前只与App组件一起使用,但它当然可以单独实现)。一旦从对话框收到肯定答复,服务就可以恢复流程。
class Authentication {
public needsAuthentication = true;
public showModal = false;
public confirm = new EventEmitter<boolean>();
public authenticate(): Observable<boolean> {
// do something to make sure authentication token works correctly
if (this.needsAuthentication) {
this.showModal = true;
return Observable.create(observer => {
this.confirm.subscribe(r => {
this.showModal = false;
this.needsAuthentication = !r;
observer.next(r);
observer.complete();
});
});
}
else {
return Observable.of(true);
}
}
}
我在这里有一个完整的实例。
http://plnkr.co/edit/C129guNJvri5hbGZGsHp?open=app%2Fapp.component.ts&p=preview
答案 1 :(得分:3)
理想情况下,请求只会“暂停”,直到用户从模式登录。我还没有找到实现这个目标的方法。
您是否尝试使用此示例中的tokenNotExpired
属性切换按钮:https://github.com/auth0/angular2-jwt#checking-authentication-to-hideshow-elements-and-handle-routing
它允许你阻止401 ...
答案 2 :(得分:3)
在我登录并收到令牌(在我的情况下在60分钟后到期)后,我设置了一个间隔,检查每分钟是否已经过了59分钟。如果是,那么我打开一个登录对话框。
然而,这个想法是登录对话框不是路由,而只是在用户碰巧所在的任何屏幕上打开的叠加层(因此我将登录组件放在app根组件的html中) ,并使用observable从应用程序的任何位置调用登录对话框)。当用户正确地重新登录时,我关闭登录对话框,用户在他们必须重新登录之前使用他们使用的任何屏幕快乐地前进。
我不知道这是不是最好的做法&#34;但它适用于您描述的情况。让我知道,我可以提出代码。
答案 3 :(得分:2)
使用浏览器会话:
https://developer.mozilla.org/de/docs/Web/API/Window/sessionStorage
将数据存储为json字符串,然后在请求失败时重新创建表单数据。
答案 4 :(得分:2)
嗯,重新加载很简单:(<any>window).location.reload(true);
最好显示登录/密码弹出窗口并允许用户继续工作,如果他可以提供密码,如果用户点击取消,只需重定向到登录页面。
还存在连接问题,超时,服务器错误。问题是使用Angular 2 Http
模块和rxjs
很难可靠地实现正确的处理。就个人而言,我放弃使用Http
模块,因为它的错误处理设计不好并实现了我自己的http模块,它允许可配置的错误处理和透明重试。