2017-10-17 222 views
1

它發現當我們攔截HTTP響應並使用subscribe獲取Observable響應中的值時,會觸發2次請求。下面是代碼攔截http響應時請求被髮送兩次

Intercerpting HTTP請求和響應通過延長它(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; 
    } 
} 

我beleive訂閱的觀察響應導致了問題。如果我們使用.subscribe的.map instad沒有問題是可重現的,但沒有得到想要的結果,例如標題值不是從響應返回的

在app.module.ts中,我們指定使用HttpService而不是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] 
    } 
    ], 

....

在服務中,我們使用POST方法來添加用戶調用服務器API。此API調用是2次,這是問題。它應該只觸發一次。 (用戶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(); 
    } 

在用戶組件,我們稱之爲使用按鈕點擊事件服務,並通過用戶模型。 (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 }); 
     } 
    ); 
    } 

我看過類似的問題在那裏解釋了有關冷熱觀測,我們應該用.share使obsevable熱,以避免這個問題。我試過了,沒有運氣。

回答

2

您的intercept方法訂閱observable並返回它。消費代碼正在訂閱相同的確切觀察值。

當涉及到Http相關的可觀察事件時,兩個訂閱意味着兩個API調用。

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

你想要做的是使用.do()操作它用於副作用。此運算符不會修改Observable類型或事件值,只是「解開」它,對值執行一些操作,並將事件向下傳遞。

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

謝謝伊戈爾索洛伊登科的回覆。 'do'解決了問題,但handleResponseHeader(response.headers)函數從未觸發。同樣的行爲也注意到了.map也注意到多個api調用沒有被注意到,但是handleResponseHeader函數從未觸發過。 –

+0

你有一個掠奪者作爲repro嗎?這兩個&地圖應該工作。您應該不惜一切代價避免雙倍訂閱。 –

+0

對不起,我的壞!有效。十分感謝。問題是我在返回之前正在應用這個做法。 –