【问题标题】:Http request made multiple times in Angular2 service在 Angular2 服务中多次发出 Http 请求
【发布时间】:2016-06-10 23:01:16
【问题描述】:

我创建了一个发出简单 GET 请求的服务:

private accountObservable = null;

constructor(private _http: Http) {
}

getAccount () {
    // If we have account cached, use it instead
    if (this.accountObservable === null) {
        this.accountObservable = this._http.get('http://localhost/api/account')
            .map(res => <Account> res.json().data)
            .catch(this.handleError);
    }

    return this.accountObservable;
}

我在我的引导函数中添加了该服务以在全局范围内提供它(我希望为所有组件提供相同的实例):

provide(AccountService, { useClass: AccountService })

问题是当我在不同的组件中调用此服务时,每次都会发出 GET 请求。因此,如果我将它添加到 3 个组件中,即使我检查了 observable 是否已经存在,也会发出 3 个 GET 请求。

ngOnInit() {
  this._accountService.getAccount().subscribe(
    account => this.account = account,
    error =>  this.errorMessage = <any>error
  );
}

如何防止多次发出 GET 请求?

【问题讨论】:

  • 您是否仅在引导级别 provideing 服务? (听起来您可能会将其列在所有组件的 providers 数组中,这将创建 3 个服务实例)。如果您只在引导级别提供它,请尝试使用Observable.share()。 (这些都是我的猜测。)
  • 另请参阅stackoverflow.com/a/35527616/215945,了解缓存服务器结果的稍微不同的实现。
  • 是的,我只在引导程序上做provide。我已经尝试在服务的构造中添加 console.log() 并且它只被触发一次。我在get() 之后添加了share(),但没有任何区别。另一个帖子也没有用。我想这是因为在我们收到数据之前,会发出一个新的请求。因此,如果 3 个组件同时运行 getAccount(),所有组件都会发出请求,并且在其中一个组件得到响应之前它不会停止。

标签: http angular


【解决方案1】:

更新后的解决方案是:

1) 将您的 getAccount() 方法更改为使用 share

getAccount () {
    // If we have account cached, use it instead
    if (this.accountObservable === null) {
        this.accountObservable = this._http.get('http://localhost/api/account')
            .pipe(share())
            .map(res => <Account> res.json().data)
            .catch(this.handleError);
    }

    return this.accountObservable;
}

2) 将import { share } from 'rxjs/operators'; 添加到.ts 文件的顶部以消除share 上的错误。

【讨论】:

    【解决方案2】:

    在我的情况下,这是因为表单发布和按钮单击设置为相同的侦听器

    【讨论】:

      【解决方案3】:

      使用Observable.share():

      if (this.accountObservable === null) {
          this.accountObservable = this._http.get('./data/data.json')
            .share()
            .map(res => res.json())
            .catch(this.handleError);
      }
      

      Plunker

      在 Plunker 中,AppComponent 和 Component2 都调用了两次getAccount().subscribe()

      对于share(),Chrome 开发者工具的网络标签会显示一个对data.json 的HTTP 请求。注释掉 share() 后,有 4 个请求。

      【讨论】:

      • 这不起作用。前段时间看到这个问题,这个解决方案,再看一遍,解决方案还是不行。
      • 另外不要忘记添加import 'rxjs/add/operator/share';@RickO'Shea 这个答案效果很好。如果它不适合你,那么你可能想发布一个 plunkr 来证明你的问题。
      • 在较新的 rxjs 上,您需要使用 pipe,因此需要更新为:.get(...).pipe(share(), map(...))。来源:learnrxjs.io/operators/multicasting/share.html
      • 这是一个更新的答案@RickO'Shea 和其他仍在试图解决这个问题的人:stackoverflow.com/a/60081534/4843137
      • 我在管道中添加了共享方法我工作的代码:.get(...).pipe(share(),
      【解决方案4】:

      有两种类型的可观察对象。

      Cold Observable:每个订阅者接收所有事件(从一开始)

      Hot observable : 每个订阅者都会收到订阅后发出的事件。

      Cold Observables 是默认的。这就是多次触发 WS 调用的原因。

      要使 Observable Hot,您必须使用以下 Rx 的运营商链:

      .publish().refCount()
      

      在你的情况下:

      getAccount () {
      
          let accountObservable = this._http.get('http://localhost/api/account')
                  .map(res => <Account> res.json().data)
                  .catch(this.handleError);
      
          return accountObservable.publish().refCount();
      }
      

      【讨论】:

      • 但这不会在每次调用getAccount() 时仍然导致HTTP 请求吗?
      • 有一个错误Property 'publish' does not exist on type 'Observable&lt;any&gt;'.
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 1970-01-01
      • 2016-11-27
      • 1970-01-01
      • 1970-01-01
      • 2015-10-23
      • 1970-01-01
      相关资源
      最近更新 更多