2

In my Angular 2+ / ASP.NET Core MVC WebAPI application I have a long running API-call from the client UI to the server. The request times out after 30 seconds. I would like to define the timeout for this specific API call either client- or server-side.

I have only found ways to configure the server timeout globally, which is not what I want, as the 30 second timeout is fine for other calls. I've also found solutions to decrease the timeout client side by piping RxJS's timeout operator. However, as I understand, this is not suitable for increasing the timeout?

How can I set the timeout on this specific request? Where does the 30 second default come from?

(The code doesn't actually matter, as it is a standard API controller and a standard Angular HTTP call):

this.http.get('api/xyz').subscribe(d => { ... });
Marc
  • 12,706
  • 7
  • 61
  • 97

2 Answers2

2

To solve the timeout issue you can use the timeout from RxJs like below

Pass time in milliseconds to timeout operator

Here I am passing 60 seconds as timeout, so after 60 seconds if there is no response from the server then it will throw timeout error.

import ‘rxjs/add/operator/timeout’; 

...

this.http.get('api/xyz').timeout(60000).subscribe(d => { ... });
TheParam
  • 10,113
  • 4
  • 40
  • 51
1

It appears that without extending HttpClientModule classes, the only expected ways for interceptors to communicate with respective requests are params and headers objects.

Since timeout value is scalar, it can be safely provided as a custom header to the interceptor.

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

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

@Injectable()
export class TimeoutInterceptor implements HttpInterceptor {
  constructor(@Inject(DEFAULT_TIMEOUT) protected defaultTimeout: number) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const timeoutValue = Number(req.headers.get('timeout')) || this.defaultTimeout;

    return next.handle(req).pipe(timeout(timeoutValue));
  }
}

This can be configured in your app module like:

...
providers: [
  [{ provide: HTTP_INTERCEPTORS, useClass: TimeoutInterceptor, multi: true }],
  [{ provide: DEFAULT_TIMEOUT, useValue: 30000 }]
],  
...

The request is then done with custom timeout header

http.get(..., { headers: new HttpHeaders({ timeout: `${20000}` }) });
Tachyon
  • 2,171
  • 3
  • 22
  • 46