angular - 在捕获到故障后,如何允许我的 HTTP 请求继续通过我的应用程序传播?

标签 angular typescript ionic-framework scope ionic2

我正在使用位于 Angular 2 之上的 Ionic 2。

我在我的应用程序中使用一项服务来处理所有 API 请求。其中一些请求带有 Authorization header 。如果身份验证失败,我的 API 可以返回 401,我目前正在通过向用户显示错误并将他们导航到登录屏幕来处理该错误。一切都很好,我为这些错误发布了一个事件,我在其他地方订阅了它来处理逻辑(因为我不能在服务中使用导航 Controller )。

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() 代码在正确的范围内?

我真的不想在服务中使用加载程序(不确定我是否能够?)因为这看起来是个糟糕的设计,而且我不想总是显示加载程序,所以它属于 Controller 。

最佳答案

您需要的是 .finally 运算符,即使 Observable 出现错误,它也会始终执行。

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 .

关于angular - 在捕获到故障后,如何允许我的 HTTP 请求继续通过我的应用程序传播?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45459966/

相关文章:

spring 和 angular2 如何使用参数请求发布数据?

node.js - Netlify TOML 文件中的默认路径设置

typescript - Angular 2 : ngModel binding for radio input of boolean type

javascript - 如何将当前系统日期与另一个日期进行比较

javascript - Ionic context.getProjectMetadata 不是函数 [仅限实时重新加载]

angular - 无法使用 Angular 5 客户端启动与信号器核心中心的连接

Angular 6浏览器检测?

angular - 错误 TS2322 : Type '() => string' is not assignable to type 'string'

angular - 从 ionic 后退按钮导航后,Ionic 4 ionViewDidEnter() 未触发

javascript - 类型错误 : Cannot read property 'includes' of undefined