当开发人员在 Dynatrace 中查看这些请求时,将无法再看到超时后正在进行的 API 调用。 该过程在后台进行渲染,但 Dynatrace 看到返回给客户端的响应并停止记录,在这种情况下,如果能了解它正在做的事情需要这么长时间,对分析问题会更有帮助。
我们可以引入一个 Angular HTTP_INTERCEPTOR 来超时等待已久的网络请求,从而确保在服务器端引导的应用程序具有更短的生命周期。 换句话说:所以 SSR 渲染不会因为等待来自网络的缓慢 API 响应而
挂起
。 但是,这可能需要在应用程序代码甚至 SSR 代码中添加额外的逻辑,以便在 SSR 响应中不会返回此类格式错误的渲染(基于不完整的数据)。 在这种情况下,最好回退到没有缓存标头的 CSR 应用程序,而不是允许格式错误的渲染 html 作为响应发送(并且可能由 CDN 缓存)。
一个例子。
在 app.module.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 { }
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(); }) ); } }
这里使用了 rxjs 的 timeout 操作符。如果在指定的时间间隔之内没有 emit 值,则会抛出 error.
看下面这个例子:
// 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));
在这段代码里,我们首先使用
delay
操作符,在 makeRequest 函数里指定了一个时间间隔,来模拟函数调用的延迟。
然后将 makeRequest 返回的 Observable,添加了一个 timeout(2500) 的操作符,意思是 2.5 秒之内,如果该 Observable 没有发出值,即进入 CatchError 的处理逻辑内。
数据源头有三个值,4000,3000 和 2000,其中只有最后一个值小于 2500,因此能在超时时间间隔之内完成函数调用。其他两个值都会导致超时,从而进入 catchError 的数据打印。
联系客服