如何仅对幂等方法重试失败的 http 请求?
How to retry failed http requests for idempotent methods only?
我正在编写一个 Angular 10 应用程序。我需要创建一个拦截器,它将重试所有失败的 idempotent HTTP 请求。在阅读了一些在线教程之后,我编写了一个我认为可以解决问题的拦截器。然后我写了一个测试来验证它是否正常工作。不幸的是,我的测试不会失败;即使我修改拦截器使测试失败,它也不会失败。
这是拦截器:
export class RetryInterceptor implements HttpInterceptor {
// private IDEMPOTENT_METHODS = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE']; // this is the real prod code.
private IDEMPOTENT_METHODS = ['POST']; // this should cause my test to fail, but it doesn't.
constructor(private router: Router, private logger: NGXLogger) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('here'); // I've confirmed that this is being printed to the console.
if (this.IDEMPOTENT_METHODS.includes(request.method)){
console.log('there'); // I've confirmed that this is being printed to the console.
return next.handle(request)
.pipe(
retry(1));
}
else{
return next.handle(request);
}
}
}
这是测试:
describe('RetryInterceptor', () => {
let httpTestingController: HttpTestingController;
let http: HttpClient;
let router: Router;
let location: Location;
let fixture;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
LoggerTestingModule,
RouterTestingModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: httpTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: RetryInterceptor,
multi: true,
},
],
});
httpTestingController = TestBed.inject(HttpTestingController);
http = TestBed.inject(HttpClient);
router = TestBed.inject(Router);
location = TestBed.inject(Location);
fixture = TestBed.createComponent(AppRootComponent);
router.initialNavigation();
});
it('should not retry POSTs', fakeAsync( // I am expecting this to fail.
() => {
http.post('/api/resource', {}).subscribe(response => expect(response).toBeTruthy());
httpTestingController.expectOne({method: 'POST', url: '/api/resource'}).error(
new ErrorEvent('network error', { message: 'bad request' }), { status: 400 });
tick(); // the first tick is intended to make a call to the httpTestingController, which will return an error, which will be caught by my Interceptor.
tick(); // on the second tick, my Interceptor should retry the failed call. this should, in turn, fail the test, because I have not set up a second expectation.
})
);
});
谁能发现我做错了什么?我的拦截器坏了吗?还是我的测试失败了?
拦截器没问题。您需要在测试结束时验证您的 http 测试控制器以捕获意外请求:
// insert this at end of test or in an afterEach() block
httpTestingController.verify()
一般来说,任何与 http 请求相关的单元测试都应该以验证结束。
文档:
https://angular.io/guide/http#testing-http-requests
https://angular.io/api/common/http/testing/HttpTestingController#verify
我正在编写一个 Angular 10 应用程序。我需要创建一个拦截器,它将重试所有失败的 idempotent HTTP 请求。在阅读了一些在线教程之后,我编写了一个我认为可以解决问题的拦截器。然后我写了一个测试来验证它是否正常工作。不幸的是,我的测试不会失败;即使我修改拦截器使测试失败,它也不会失败。
这是拦截器:
export class RetryInterceptor implements HttpInterceptor {
// private IDEMPOTENT_METHODS = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'PUT', 'TRACE']; // this is the real prod code.
private IDEMPOTENT_METHODS = ['POST']; // this should cause my test to fail, but it doesn't.
constructor(private router: Router, private logger: NGXLogger) {}
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
console.log('here'); // I've confirmed that this is being printed to the console.
if (this.IDEMPOTENT_METHODS.includes(request.method)){
console.log('there'); // I've confirmed that this is being printed to the console.
return next.handle(request)
.pipe(
retry(1));
}
else{
return next.handle(request);
}
}
}
这是测试:
describe('RetryInterceptor', () => {
let httpTestingController: HttpTestingController;
let http: HttpClient;
let router: Router;
let location: Location;
let fixture;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientTestingModule,
LoggerTestingModule,
RouterTestingModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: httpTranslateLoader,
deps: [HttpClient]
}
})
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: RetryInterceptor,
multi: true,
},
],
});
httpTestingController = TestBed.inject(HttpTestingController);
http = TestBed.inject(HttpClient);
router = TestBed.inject(Router);
location = TestBed.inject(Location);
fixture = TestBed.createComponent(AppRootComponent);
router.initialNavigation();
});
it('should not retry POSTs', fakeAsync( // I am expecting this to fail.
() => {
http.post('/api/resource', {}).subscribe(response => expect(response).toBeTruthy());
httpTestingController.expectOne({method: 'POST', url: '/api/resource'}).error(
new ErrorEvent('network error', { message: 'bad request' }), { status: 400 });
tick(); // the first tick is intended to make a call to the httpTestingController, which will return an error, which will be caught by my Interceptor.
tick(); // on the second tick, my Interceptor should retry the failed call. this should, in turn, fail the test, because I have not set up a second expectation.
})
);
});
谁能发现我做错了什么?我的拦截器坏了吗?还是我的测试失败了?
拦截器没问题。您需要在测试结束时验证您的 http 测试控制器以捕获意外请求:
// insert this at end of test or in an afterEach() block
httpTestingController.verify()
一般来说,任何与 http 请求相关的单元测试都应该以验证结束。
文档:
https://angular.io/guide/http#testing-http-requests https://angular.io/api/common/http/testing/HttpTestingController#verify