web-dev-qa-db-ja.com

デフォルトおよび特定のリクエストタイムアウト

通常、すべてのリクエストに適用され、特定のlongerリクエスト(例:600秒)でオーバーライドできるデフォルトのタイムアウト(例:30秒)が望ましいです。

私の知る限り、Httpサービスでデフォルトのタイムアウトを指定する良い方法はありません。

HttpClientサービスでこれにアプローチする方法は何ですか?すべての発信リクエストに対してデフォルトのタイムアウトを定義する方法は、特定のリクエストに対してオーバーライドできますか?

31
Estus Flask

HttpClientModuleクラスを拡張することなく、インターセプターがそれぞれのリクエストと通信するために期待される唯一の方法はparamsおよびheadersオブジェクトであるようです。

タイムアウト値はスカラーであるため、インターセプターにカスタムヘッダーとして安全に提供できます。RxJStimeout演算子を使用して適用する必要があるデフォルトのタイムアウトか特定のタイムアウトかを決定できます。

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));
  }
}

これは、アプリモジュールで次のように構成できます。

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

その後、リクエストはカスタムtimeoutヘッダーで行われます

http.get(..., { headers: new HttpHeaders({ timeout: `${20000}` }) });

ヘッダーは文字列であるため、タイムアウト値は最初に文字列に変換する必要があります。

デモ です。

timeoutでインターセプターを使用するというアイデアを提案した功績は、@ RahulSinghと@ Jota.Toledoに与えられます。

69
Estus Flask

新しいHttpClientを使用すると、このようなことを試すことができます

@Injectable()
export class AngularInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    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に登録する

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        HttpClientModule
    ],
    providers: [
        [ { provide: HTTP_INTERCEPTORS, useClass: 
              AngularInterceptor, multi: true } ]
    ],
    bootstrap: [AppComponent]
})
export class AppModule {
}
10
Rahul Singh

次のように、ベースタイムアウト値でグローバルインターセプターを作成できます。

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';

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

その後、このインジェクタブルをルートモジュールのプロバイダー配列に登録する必要があります。

トリッキーな部分は、特定のリクエストのデフォルト時間(増加/減少)をオーバーライドすることです。今のところ、これを解決する方法がわかりません。

9
Jota.Toledo