How does angular implement timeout monitoring of HTTP requests through HTTP interceptor

Time:2022-5-23

When developers view these requests in dynatrace, they will no longer see the API calls in progress after the timeout. This process is rendered in the background, but dynatrace sees the response returned to the client and stops recording. In this case, if it takes so long to understand what it is doing, it will be more helpful to analyze the problem.

We can introduce an angular http_ Interceptor to time out long-awaited network requests, ensuring a shorter life cycle of applications booted on the server side. In other words: therefore, SSR rendering will not be delayed by waiting for a slow API response from the networkHang。 However, this may require adding additional logic to the application code or even the SSR code so that such malformed renderings (based on incomplete data) are not returned in the SSR response. In this case, it is better to fall back to a CSR application without a cached header, rather than allowing malformed rendered HTML to be sent as a response (and possibly cached by CDN).

An example.

On app module. Code in TS:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { RequestTimeoutHttpInterceptor, DEFAULT_TIMEOUT } from './interceptors';
import { AppComponent } from './app.component';

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule,
  ],
  declarations: [
    AppComponent,
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: RequestTimeoutHttpInterceptor, multi: true },
    { provide: DEFAULT_TIMEOUT, useValue: 5000 },
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

Implementation of Interceptor:

import { Injectable, InjectionToken, Inject } from '@angular/core';
import { HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { empty, TimeoutError } from 'rxjs';
import { timeout, catchError } from 'rxjs/operators';

export const DEFAULT_TIMEOUT = new InjectionToken<number>('defaultTimeout');

@Injectable({
  providedIn: 'root'
})
export class RequestTimeoutHttpInterceptor implements HttpInterceptor {

  constructor(
    @Inject(DEFAULT_TIMEOUT) protected defaultTimeout: number,
  ) { }

  intercept(req: HttpRequest<any>, next: HttpHandler) {
    const modified = req.clone({
      setHeaders: { 'X-Request-Timeout': `${this.defaultTimeout}` }
    });

    return next.handle(modified).pipe(
      timeout(this.defaultTimeout),
      catchError(err => {
        if (err instanceof TimeoutError)
          console.error('Timeout has occurred', req.url);
        return empty();
      })
    );
  }

}

The timeout operator of rxjs is used here. If there is no emit value within the specified time interval, an error is thrown

Take the following example:

// RxJS v6+
import { of } from 'rxjs';
import { concatMap, timeout, catchError, delay } from 'rxjs/operators';

// simulate request
function makeRequest(timeToDelay) {
  return of('Request Complete!').pipe(delay(timeToDelay));
}

of(4000, 3000, 2000)
  .pipe(
    concatMap(duration =>
      makeRequest(duration).pipe(
        timeout(2500),
        catchError(error => of(`Request timed out after: ${duration}`))
      )
    )
  )
  /*
   *  "Request timed out after: 4000"
   *  "Request timed out after: 3000"
   *  "Request Complete!"
   */
  .subscribe(val => console.log(val));

In this code, we first usedelayOperator, which specifies a time interval in the makerequest function to simulate the delay of function call.

Then add a timeout (2500) operator to the observable returned by makerequest, which means that if the observable does not send a value within 2.5 seconds, it will enter the processing logic of catchrror.

The data source has three values, 40003000 and 2000, of which only the last value is less than 2500, so the function call can be completed within the timeout interval. The other two values will cause a timeout and enter the data printing of catchrror.