简体   繁体   中英

How to hold off certain HTTP requests at HTTP Interceptor in Angular

I have an Angular code and the story behind is as this. I have 3 HTTP calls and from one call I need a special header (X) that is required by the other two HTTP calls and I can't control the execution of these calls. So when a HTTP call that requires the X header goes before the HTTP call which gives me the X header, how can I hold off the call and let the particular HTTP call go and acquire the X header and continue the rest of the calls with the X header appended to the rest of the HTTP calls? It may seem like I'm trying to create a HTTP call queue until I get the X header and continue the rest of the calls again. Some help would be appreciated. The code is as follows.

template:

<button class="btn btn-primary" (click)="do()"> Do </button>

App.ts file

 export class AppComponent {
  constructor(private dataService: DataService) {}
  public do(): void {
    this.dataService.first().subscribe();
    this.dataService.second().subscribe((res) => {
      this.dataService.third().subscribe();
    });
  }
}

data-service.ts which has the 3 HTTP calls

const httpOptions1 = {
  headers: new HttpHeaders({ 'A': 'A' })
};

const httpOptions2 = {
  headers: new HttpHeaders({ 'X': 'X' })
};

const httpOptions3 = {
  headers: new HttpHeaders({ 'B': 'B' })
};

@Injectable()
export class DataService {

  private apiUrl = 'https://jsonplaceholder.typicode.com/posts';

  constructor(private http: HttpClient) {}

  public first(): Observable<any> {
    console.log('Call One')
    return this.http.get(`${this.apiUrl}`, httpOptions1);
  }

  public second(): Observable<any> {
    console.log('Call Two')
    return this.http.get(`${this.apiUrl}`, httpOptions2);
  }

  public third(): Observable<any> {
    console.log('Call Three')
    return this.http.get(`${this.apiUrl}`, httpOptions3);
  }
}

It is the second call which has my X header and from the Interceptor what I want to do is that when the first() call goes off, I want to hold it add and let the second() call go and acquire the X header and then re-run the first() call from the interceptor level.

Below is the code of the Interceptor

private pocessed: boolean = false;
  private queue: any[] = [];

  constructor() {}

  public intercept(req: HttpRequest<any>, delegate: HttpHandler): Observable<any> {
        /**
         * Filter a certain http call with a certain X http header where this call provides a new header
         * to be appended to all other http calls
         */
        if (req.headers.has('X')) {
            return delegate.handle(req).do((event) => {
                if (event.type === HttpEventType.Response) {
                    // new header data acquired; hence the boolean turned to true
                    this.pocessed = true;
                }
            });
        } else if (this.pocessed) {
            /**
             * if new header data acquired, append the new header to the rest of the calls
             */
            if (this.queue.length > 0) {
                // append header data to previous http calls
                this.queue.forEach(element => {
                    let request = new HttpRequest(element.req['method'], element.req['url'], element.req['body'], {
                        headers: element.req['headers'],
                        reportProgress: true,
                        params: element.req['params'],
                        responseType: element.req['responseType'],
                        withCredentials: element.req['withCredentials']
                    });

                    // this.fakeIntercept(request, element.next);
                });
            }
            // if new header data acquired, append the header to the rest of the calls
            req = req.clone({ setHeaders: { 'X': 'X' } });
            return delegate.handle(req).do((event) => console.log(event));
        } else {
            /**
             * these http calls need X header but the call to get the X header hasnt gone yet
             * therefor storing these calls in a queue to be used later when the header arrives
             */
            this.queue.push({req: req, next: delegate});
            return Observable.empty<any>();
        }
    }

    fakeIntercept(req: HttpRequest<any>, delegate: HttpHandler): Observable<any> {
        req = req.clone({ setHeaders: { 'X': 'X' } });
        return delegate.handle(req);
    }

If you guys need any clarification please hit me up in the comments. If you see anything I've done wrong here please do share with me. Any improvements to the code is welcome.

I found a solution and its pretty good for me atm. I'm using a SUbject stream to mimic the behavior of a Queue and let requests stack up Until I get the data from the X header http call. Below is the code. Hope it makes sense. Cheers!

public intercept(req: HttpRequest<any>, delegate: HttpHandler): Observable<any> {
        return Observable.create(observer => {
            if (req.headers.has('X') && this.headerAcquired == false) {
                this.headerAcquired = true;
                const subscription = delegate.handle(req).subscribe(event => {
                    if (event instanceof HttpResponse) {
                        this.pocessed = true;
                        this.requestSetter({key: this.pocessed});
                        this.removeRequest(req);
                        observer.next(event);
                    }
                },
                err => {
                    this.removeRequest(req);
                    observer.error(err);
                },
                () => {
                    this.removeRequest(req);
                    observer.complete();
                });
                // remove request from queue when cancelled
                return () => {
                    this.removeRequest(req);
                    subscription.unsubscribe();
                };
            } else {
                this.requests.push(req);

                this.requestGetter().subscribe(res => {
                    const i = this.requests.indexOf(req);
                    if (i >= 0) {
                        this.subjectInit = true;
                        this.requests.splice(i, 1);
                        req = req.clone({ setHeaders: { 'X': 'X' } });
                        const subscription = delegate.handle(req).subscribe(event => {
                            if (event instanceof HttpResponse) {
                                this.pocessed = true;
                                this.request.next(true);
                                this.removeRequest(req);
                                observer.next(event);
                            }
                        },
                        err => {
                            this.removeRequest(req);
                            observer.error(err);
                        },
                        () => {
                            this.subjectInit = false;
                            this.removeRequest(req);
                            observer.complete();
                        });
                        // remove request from queue when cancelled
                        return () => {
                            this.removeRequest(req);
                            subscription.unsubscribe();
                            this.request.unsubscribe();
                        };
                    }
                });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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