0

TL;DR;

Why subscribing to an Observable in an http interceptor produces duplicate http requests to server?

Sample code:

  doGetWithInterceptor() {
    console.log("Http get with interceptor -> 2 http calls ?? Why?");
    this.http_interceptor_get("http://ip.jsontest.com/").subscribe(data => {
      console.log("But only one block of data received:", data);
      this.result= data.ip;
    });
  }

  http_interceptor_get(url : string)  {
    let req= this.http.get(url).map(res => res.json());

    req.subscribe((data) => {
      console.log("[HttpInterceptor]");
    });

    return req;
  }

Full details:

I use an http interceptor service in my Ionic 2 project to globally detect errors, authentication, and more...

But doing so, I am seeing duplicate http requests to the server.

I have an small test App starting from a blank Ionic 2 template:

Test App

Which clearly shows the problem in Firebug:

  • First request (it's ok, single) if using the GET button.
  • Second request (which duplicates) is using the "Get with interceptor" button.

Meanwhile, the code in the subscription part is executed only once, as it should.

Interceptor produces 2 http requests

The home.ts code is as follows:

import { Component } from '@angular/core';

import { NavController } from 'ionic-angular';

import { Http, Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  result : string = "???";

  constructor(public navCtrl: NavController, public http: Http) {
  }

  http_get(url : string)  {
    return this.http.get(url).map(res => res.json());
  }

  http_interceptor_get(url : string)  {
    let req= this.http.get(url).map(res => res.json());

    req.subscribe((data) => {
      console.log("[HttpInterceptor]");
    });

    return req;
  }

  doGet() {
    console.log("Normal http get -> 1 http call");
    this.http_get("http://ip.jsontest.com/").subscribe(data => {
      console.log("One block of data received:", data);
      this.result= data.ip;
    });
  }

  doGetWithInterceptor() {
    console.log("Http get with interceptor -> 2 http calls ?? Why?");
    this.http_interceptor_get("http://ip.jsontest.com/").subscribe(data => {
      console.log("But only one block of data received:", data);
      this.result= data.ip;
    });
  }

  doClearResult() {
    this.result= "???";
  }

}
jrierab
  • 605
  • 5
  • 15

1 Answers1

1

Its because you are not really intercepting. You are simply subscirbing to the request twice.

http_interceptor_get(url : string)  {
    let req= this.http.get(url).map(res => res.json());

    req.subscribe((data) => {   //1st subscription - 1st call
      console.log("[HttpInterceptor]");
    });

    return req; //return original request
  }

Then you are subscribing again in doGetWithInterceptor() to your http req.

If you want to log details of call, you can use do().

 http_interceptor_get(url : string)  {
            //return http call
  return this.http.get(url).map(res => res.json())
        .do(data=>{
        //do checks.
        return data; //be sure to return data so it is passed on to subscription.
         });
    }

Then call in your doGetWithInterceptor()

Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
  • The _.do_ does the trick. I was somehow thinking that the Observable would perform the operation (once) and then provide the data to all of its subscribers (twice in my case), something similar like an event emitter-receiver. Many thanks for your quick answer ! – jrierab Jan 20 '17 at 16:30
  • http://stackoverflow.com/questions/37771855/chaining-observables-in-rxjs is this what you are looking for? or http://stackoverflow.com/questions/25634375/rxjs-only-the-first-observer-can-see-data-from-observable-share ? – Suraj Rao Jan 20 '17 at 16:48
  • Well, I would like to create an httpInterceptor which should take care of 404 and similar errors (in a catch?), and also 'unauthorized' errors returned from server (which are verified in the .do part). If all is ok, the info should be returned to the caller, which will process it as needed. It seems to me that I should dive deeper in the Obrservable/Subject/... sea :-) – jrierab Jan 20 '17 at 17:05
  • you dont need to deep dive for error handling http://stackoverflow.com/questions/36666452/can-i-catch-certain-errors-before-subscribe-in-an-rxjs-observable-in-angular – Suraj Rao Jan 20 '17 at 17:18
  • Yes. That was the missing piece. Thanks again for your support @suraj. – jrierab Jan 23 '17 at 08:48