简体   繁体   English

拦截http响应时请求发送两次

[英]Request is sent twice when intercepting http response

It's noticed that the request is triggered twice when we intercept HTTP response and use subscribe to get the value in the Observable response.注意到当我们拦截HTTP响应并使用subscribe获取Observable响应中的值时,请求被触发了两次。

Here is the code :这是代码:

Intercerpting Http Request and Response by extending it (http.service.ts)通过扩展拦截 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;
    }
}

I believe subscribing to the observable response is causing the issue.我相信订阅可观察的响应是导致问题的原因。 If we use .map instad of .subscribe, no issue is reproducible but not getting the desired result like the header values are not returned from the response如果我们使用 .subscribe 的 .map instad,则没有问题是可重现的,但无法获得所需的结果,例如响应不会返回标头值

In app.module.ts we specify to use HttpService instead of Http (app.module.ts)在 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]
    }
  ],

.... ....

In the service, we call server API using post method to add a user.在服务中,我们使用 post 方法调用服务器 API 来添加用户。 This API call is made twice and that is the issue.这个 API 调用进行了两次,这就是问题所在。 It should be trigger only once.它应该只触发一次。 (User-operation.service.ts) (用户操作.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 the user component, we call the service using a button click event and pass the user model.在用户组件中,我们使用按钮单击事件调用服务并传递用户模型。 (User.component.ts) (用户.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 });
      }
      );
  }

I have read about similar issues which explains cold and hot observables and we should use .share to make the obsevable hot and to avoid the issue.我已经阅读了解释冷和热可观察的类似问题,我们应该使用 .share 使可观察变得热并避免这个问题。 I tried that and I had no luck.我试过了,但我没有运气。

Your intercept method subscribes to an observable, and returns it.您的intercept方法订阅了一个可观察对象,并返回它。 This same exact observable is being subscribed to by the consuming code.消费代码订阅了这个完全相同的 observable。

Two subscriptions mean two API calls when it comes to Http-related observables.当涉及到与 Http 相关的 observable 时,两个订阅意味着两个 API 调用。

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

What you want to do is use the .do() operator which is used for side effects.您想要做的是使用用于副作用的.do()运算符。 This operator does not modify the Observable type nor event value, just "unwraps" it, performs some work on the value, and passes the event down the stream.此运算符不修改 Observable 类型或事件值,只是“解包”它,对值执行一些工作,并将事件向下传递。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM