关于angular:默认和特定请求超时

Default and specific request timeout

通常最好将默认超时(例如30秒)应用于所有请求,并且可以为特定的较长请求(例如600秒)覆盖。

据我所知,没有很好的方法在Http服务中指定默认超时。

HttpClient服务中解决此问题的方法是什么?如何为所有传出请求定义默认超时,可以为特定请求覆盖默认超时?


似乎没有扩展HttpClientModule类,拦截器与各个请求进行通信的唯一预期方式是paramsheaders对象。

由于超时值为标量,因此可以安全地将其作为自定义标头提供给拦截器,在拦截器中可以确定它是默认超时还是应通过RxJS timeout运算符应用的特定超时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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, next: HttpHandler): Observable<HttpEvent> {
    const timeoutValue = req.headers.get('timeout') || this.defaultTimeout;
    const timeoutValueNumeric = Number(timeoutValue);

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

可以在您的应用模块中进行配置,例如:

1
2
3
4
providers: [
  [{ provide: HTTP_INTERCEPTORS, useClass: TimeoutInterceptor, multi: true }],
  [{ provide: DEFAULT_TIMEOUT, useValue: 30000 }]
],

然后使用自定义的timeout标头

完成请求

1
http.get('/your/url/here', { headers: new HttpHeaders({ timeout: `${20000}` }) });

由于标头应为字符串,因此应将超时值首先转换为字符串。

这是一个演示。

感谢@RahulSingh和@ Jota.Toledo建议使用与timeout一起使用拦截器的想法。


作为其他答案的补充,请注意,如果您在开发机上使用代理配置,则代理的默认超时为120秒(2分钟)。对于更长的请求,您需要在配置中定义一个更高的值,否则这些答案都不起作用。

1
2
3
4
5
6
7
{
 "/api": {
   "target":"http://localhost:3000",
   "secure": false,
   "timeout": 360000
  }
}


您可以使用基本超时值创建全局拦截器,如下所示:

1
2
3
4
5
6
7
8
9
10
import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';

@Injectable()
export class AngularInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
    return next.handle(req).timeout(30000, Observable.throw("Request timed out"));
    // 30000 (30s) would be the global default for example
  }
}

之后,您需要在根模块的providers数组中注册此可注射物。

棘手的部分是要覆盖特定请求的默认时间(增加/减少)。目前,我不知道该如何解决。


使用新的HttpClient,您可以尝试这样的事情

1
2
3
4
5
6
7
8
9
10
11
@Injectable()
export class AngularInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest, next: HttpHandler): Observable<HttpEvent> {
    return next.handle(req).timeout(5000).do(event => {}, err => { // timeout of 5000 ms
        if(err instanceof HttpErrorResponse){
            console.log("Error Caught By Interceptor");
            //Observable.throw(err);
        }
    });
  }
}

向传递的next.handle(req)添加超时。

一样在AppModule中注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        HttpClientModule
    ],
    providers: [
        [ { provide: HTTP_INTERCEPTORS, useClass:
              AngularInterceptor, multi: true } ]
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}