2017-10-17 4 views
1

Es wurde festgestellt, dass Anforderung 2 mal ausgelöst wird, wenn wir HTTP-Antwort abfangen und subscribe verwenden, um den Wert in Observable-Antwort zu erhalten. Im Folgenden finden Sie den CodeAnforderung wird zweimal gesendet, wenn HTTP-Antwort abgefangen wird

Intercerpting Http Request und Response durch (http.service.ts)

import { Injectable } from '@angular/core'; 
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers, ConnectionBackend } from '@angular/http'; 
import { Observable } from 'rxjs/Observable'; 
import 'rxjs/add/operator/map'; 
import 'rxjs/add/operator/catch'; 
import { LoggedInUserApi } from './loggedInUser.service'; 

@Injectable() 
export class HttpService extends Http { 

    constructor(private loggedInUserApi: LoggedInUserApi, backend: XHRBackend, options: RequestOptions) { 
     super(backend, options); 
    } 

    request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { 
     return this.intercept(super.request(url, options)); 
    } 

    get(url: string, options?: RequestOptionsArgs): Observable<Response> { 
     return this.intercept(super.get(url, options)); 
    } 

    post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> { 
     return this.intercept(super.post(url, body, options)); 
    } 

    put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> { 
     return this.intercept(super.put(url, body, options)); 
    } 

    delete(url: string, options?: RequestOptionsArgs): Observable<Response> { 
     return this.intercept(super.delete(url, options)); 
    } 
    handleResponseHeader(header) { 
     console.log(header); 
    } 
    intercept(observableResponse: Observable<Response>): Observable<Response> { 
     observableResponse.subscribe(response => this.handleResponseHeader(response.headers)); 
     return observableResponse; 
    } 
} 

Ich glaube, der abonnieren möchte die beobachtbare Reaktion Verlängerung das Problem verursacht. Wenn wir .map instad von .subscribe verwenden, ist kein Problem reproduzierbar, aber nicht das gewünschte Ergebnis, wie die Headerwerte nicht von Antwort

zurückgegeben werden. In app.module.ts geben wir an, HttpService anstelle von Http (App. module.ts)

..... 
providers: [ 
    ...... 
    { 
     provide: Http, 
     useFactory: (loggedInUserApi: service.LoggedInUserApi, xhrBackend: XHRBackend, requestOptions: RequestOptions) => 
     new service.HttpService(loggedInUserApi, xhrBackend, requestOptions), 
     deps: [service.LoggedInUserApi, XHRBackend, RequestOptions] 
    } 
    ], 

....

In-Service, rufen wir Server-API post-Methode mit einem Benutzer hinzuzufügen. Dieser API-Aufruf erfolgt 2-mal und das ist das Problem. Es sollte nur einmal ausgelöst werden. (User-operation.service.ts)

public addUser(body: models.User, extraHttpRequestParams?: any): Observable<models.User> { 
     // verify required parameter 'body' is not null or undefined 
     if (body === null || body === undefined) { 
      throw new Error('Required parameter body was null or undefined when calling addUser.'); 
     } 

     const path = this.basePath + '/user'; 

     let queryParameters = new URLSearchParams(); 
     let headerParams = new Headers({ 'Content-Type': 'application/json' }); 

     let requestOptions: RequestOptionsArgs = { 
      method: 'POST', 
      headers: headerParams, 
      search: queryParameters 
     }; 
     requestOptions.body = JSON.stringify(body); 

     return this.http.request(path, requestOptions) 
      .map((response: Response) => { 
       if (response.status === 204) { 
        return undefined; 
       } else { 
        return response.json(); 
       } 
      }).share(); 
    } 

In Benutzerkomponente, rufen wir den Service auf eine Schaltfläche klicken Ereignis verwenden und das Benutzermodell übergeben. (User.component.ts)

addUser(event) { 
    // To add user using api 
    this.busy = this.api.addUser(this.user) 
     .subscribe(
    () => { 
     DialogService.displayStatusMessage({ message: 'User configurations saved successfully.', type: 'success' }); 
     this.router.navigate(['users']); 
     }, 
     (error: any) => { 
     throw ({ message: error.json().message }); 
     } 
    ); 
    } 

ich zu ähnlichen Problemen gelesen haben, wo es zu kalt und heiß Observablen erklärt und wir sollten .share die obsevable heiß zu machen verwenden und das Problem zu vermeiden. Ich habe das versucht und habe kein Glück.

Antwort

2

Ihre intercept Methode abonniert eine Observable und gibt sie zurück. Dieselbe genaue Observable wird von dem konsumierenden Code abonniert.

Zwei Subskriptionen bedeuten zwei API-Aufrufe, wenn es um Http-verwandte Observables geht.

intercept(observableResponse: Observable<Response>): Observable<Response> { 
    observableResponse 
     .subscribe(response =>       // <-- pretty bad! 
     this.handleResponseHeader(response.headers) 
    ); 
    return observableResponse; 
} 

Was möchten Sie tun, ist zu verwenden, um die .do() Betreiber, die für Nebenwirkungen verwendet wird. Dieser Operator ändert weder den Observable-Typ noch den Event-Wert, sondern "entwirrt" ihn, führt einige Arbeiten an dem Wert durch und übergibt das Ereignis im Stream.

intercept(observableResponse: Observable<Response>): Observable<Response> { 
    return observableResponse 
     .do(response => this.handleResponseHeader(response.headers)); 
} 
+0

Danke, Igor Soloydenko für die Antwort. Das 'do' löst das Problem, aber die Funktion 'handleResponseHeader (response.headers)' wurde nie ausgelöst. Gleiches Verhalten wird mit .map auch bemerkt, wo der mehrfache api Anruf nicht bemerkt wird, aber die handleResponseHeader Funktion nie ausgelöst wird. –

+0

Haben Sie einen Plünderer als Repro? Beide tun & map sollte funktionieren. Sie sollten doppelte Abonnements um jeden Preis vermeiden. –

+0

Entschuldigung, mein Schlechter !!. Es funktionierte. Vielen Dank. Das Problem war, dass ich das Do vor der Rückkehr anwendete. –

Verwandte Themen