我正在使用位于Angular 2之上的Ionic 2。
我正在使用应用程序中的服务来处理所有 API 请求。 其中一些请求带有授权标头。 如果身份验证失败,我的 API 可以返回 401,我目前正在通过向用户显示错误并将其导航到登录屏幕来处理这个问题。 这一切都很好用,我为这些错误发布了一个事件,我在其他地方订阅了该事件来处理逻辑(因为我不能在服务中使用导航控制器(。
api.js
服务代码:
@Injectable()
export class Api {
base_url: string = 'https://***.com';
url: string = this.base_url + '/api/v1';
authurl: string = this.base_url + '/oauth/token';
grant_type: string = 'password';
client_id: string = '1';
client_secret: string = '***';
access_token: string;
constructor(
public http: Http,
private storage: Storage,
public events: Events) {
// Grab access token and store it
storage.get('access_token').then((val) => {
this.access_token = val;
});
}
// Performs a GET request with auth headers
get(endpoint: string, params?: any) {
if(!params) {
params = [];
}
params['grant_type'] = this.grant_type;
params['client_id'] = this.client_id;
params['client_secret'] = this.client_secret;
let headers: Headers = this.getHeaders();
return this.getApiToken().flatMap(data => {
headers.append('Authorization', 'Bearer ' + data);
let options = new RequestOptions({ headers: headers });
// Support easy query params for GET requests
if (params) {
let p = new URLSearchParams();
for (let k in params) {
p.set(k, params[k]);
}
// Set the search field if we have params and don't already have
// a search field set in options.
options.search = !options.search && p || options.search;
}
return this.http.get(this.url + '/' + endpoint, options)
.catch((error: any) => {
if (error.status === 500) {
this.events.publish('api:generalError', error);
return Observable.throw(new Error(error.status));
}
else if (error.status === 401) {
this.events.publish('api:unauthorized', error);
return Observable.throw(new Error(error.status));
}
});
}).share();
}
}
问题归结为"正在加载..."在get
请求发生时向用户显示的对话框。 在调用该方法之前,我创建一个加载对话框,并在成功或失败时将其关闭。 问题是我在api.js
内部没有任何范围,以便在捕获 401 或 500 时将其关闭。
以下是我围绕此的逻辑示例:
let loader = this.loadingCtrl.create({
content: "Please wait..."
});
loader.present();
this.trainingProgramme.get_programmes()
.map(res => res.json())
.subscribe((res) => {
this.currentItems = res.training_programmes;
}, (err) => {
// Error
console.log(err);
}, () => {
loader.dismiss();
});
我认为这并不重要,但我为每个实体都有一个服务,而该服务又调用api.js
服务。 在上面的例子中,它是this.trainingProgramme
,看起来像这样:
get_programmes() {
let seq = this.api.get('training-programmes');
seq
.subscribe();
return seq;
}
我认为我处理这个问题的方式都是正确的,但是我看不到可以处理"加载"问题的方法。
有没有办法让get
方法即使在捕获错误后仍继续在我的应用程序中运行,以便我的loader.dismiss()
代码在正确的范围内运行?
我真的不想在服务中使用加载器(不确定我什至能够吗?(,因为这似乎是糟糕的设计,而且我不想总是显示加载器,所以它属于控制器。
您需要的是.finally
运算符,即使 Observable 上出现错误,该运算符也将始终执行。
如果发生error
,将不会触发complete
回调(.subscribe
调用中的最后一个回调(。
请记住包括它:
import 'rxjs/add/operator/finally';
...
this.trainingProgramme.get_programmes()
.finally(() => loader.dismiss())
.map(res => res.json())
.subscribe((res) => {
...
}
, (err) => {
// Error
console.log(err);
});
顺便说一下,考虑将您的代码从@angular/http
更新到新HttpClient
.