此拦截器的目标是在服务器需要captcha密钥时重新发送请求。
但是,当应该刷新jwt令牌时,可以使用它。
拦截器工作正常,但我无法解释为什么测试失败。
--如果响应代码!= 200.,流将永远不会传递到httpClient.get('/error').subscribe()
下面是一个可复制演示的链接:https://stackblitz.com/edit/angular-testing-template-mfqwpj?embed=1&file=app/interceptor.spec.ts
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs';
import {Injectable} from '@angular/core';
import {catchError, switchMap} from 'rxjs/operators';
import {CaptchaHeader, CaptchaV2Service} from 'century-lib';
@Injectable({
providedIn: 'root'
})
export class CaptchaInterceptor implements HttpInterceptor {
constructor(private captchaService: CaptchaV2Service) {
}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req).pipe(
catchError(err => {
if (!this.captchaIsRequired(err)) {
return;
}
return this.captchaService.getCaptchaKey().pipe(
switchMap((key) => {
const newReq = this.applyCaptchaKey(req, key);
return next.handle(newReq);
})
);
})
);
}
applyCaptchaKey(req, key) {
return req.clone({
headers: req.headers.set('Captcha-Token', key)
});
}
private captchaIsRequired(error) {
return (error.status === 400 && error.headers.get('Captcha-Status') === 'required');
}
}测试:
import {async, TestBed} from '@angular/core/testing';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {CaptchaV2Service} from 'century-lib';
import {HTTP_INTERCEPTORS, HttpClient, HttpHeaders} from '@angular/common/http';
import {CaptchaInterceptor} from './captcha.interceptor';
import {EventEmitter} from '@angular/core';
class MockCaptchaService {
valid = new EventEmitter<string>();
reset = new EventEmitter<boolean>();
getCaptchaKey() {
setTimeout(() => {
this.valid.emit('captcha-key');
}, 500);
return this.valid;
}
}
describe('Captcha interceptor', () => {
let httpClient: HttpClient;
let httpMock: HttpTestingController;
let interceptor: CaptchaInterceptor;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
CaptchaInterceptor,
{provide: CaptchaV2Service, useValue: new MockCaptchaService()},
{provide: HTTP_INTERCEPTORS, useClass: CaptchaInterceptor, multi: true},
]
});
httpClient = TestBed.get(HttpClient);
httpMock = TestBed.get(HttpTestingController);
interceptor = TestBed.get(CaptchaInterceptor);
});
it('should construct', async(() => {
expect(interceptor).toBeDefined();
}));
it('Should interrogate the captchaService when service returns Captcha-Required', async(() => {
httpClient.get('/error').subscribe(() => {
}, () => {
});
const req = httpMock.expectOne('/error');
req.error(new ErrorEvent('Captcha Error'), {
status: 400,
statusText: 'Captcha-Error',
headers: new HttpHeaders().set('Captcha-Status', 'required')
});
expect(req.request.headers.get('Captcha-Token')).toBe('captcha-key');
httpMock.verify();
}));
afterEach(() => {
TestBed.resetTestingModule();
});
});发布于 2018-09-11 12:08:29
const req = httpMock.expectOne('/error');
req.error(new ErrorEvent('Captcha Error'), {
status: 400,
statusText: 'Captcha-Error',
headers: new HttpHeaders().set('Captcha-Status', 'required')
});
expect(req.request.headers.get('Captcha-Token')).toBe('captcha-key');这没有任何意义。您只有一个请求req,并使用错误刷新它。这很好,但此时请求已经完成,什么也不会完成(您已经收到了请求,得到了响应)。
现在,最后一行期望完全相反--完成的请求将在某种程度上发生变化。
这不是你的拦截器要做的。拦截器正在发出另一个请求以获取新令牌(或验证captcha),然后重新尝试原始请求。删除expect和mock.verify()将显示已经发出的所有请求。
发布于 2018-09-11 14:46:49
这是我的最后一个测试:
import {async, fakeAsync, TestBed, tick} from '@angular/core/testing';
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
import {CaptchaV2Service} from 'century-lib';
import {HTTP_INTERCEPTORS, HttpClient, HttpHeaders} from '@angular/common/http';
import {CaptchaInterceptor} from './captcha.interceptor';
import {Observable} from 'rxjs';
function ObservableDelay<T>(val: T, delay: number, cb = () => {
}): Observable<any> {
return new Observable(observer => {
setTimeout(() => {
observer.next(val);
observer.complete();
cb();
}, delay);
});
}
const CAPTCHA_TOKEN = 'captcha-token';
describe('Captcha interceptor', () => {
let httpClient: HttpClient;
let httpMock: HttpTestingController;
let interceptor: CaptchaInterceptor;
let captchaService: CaptchaV2Service;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [
CaptchaInterceptor,
{provide: CaptchaV2Service, useClass: CaptchaV2Service},
{provide: HTTP_INTERCEPTORS, useClass: CaptchaInterceptor, multi: true},
]
});
httpClient = TestBed.get(HttpClient);
httpMock = TestBed.get(HttpTestingController);
interceptor = TestBed.get(CaptchaInterceptor);
captchaService = TestBed.get(CaptchaV2Service);
});
it('should construct', async(() => {
expect(interceptor).toBeDefined();
}));
it('Should interrogate the captchaService when service returns Captcha-Required', fakeAsync(() => {
spyOn(captchaService, 'getCaptchaKey').and.returnValue(ObservableDelay(CAPTCHA_TOKEN, 200, () => {
httpMock
.expectOne(r => r.headers.has('Captcha-Token') && r.headers.get('Captcha-Token') === CAPTCHA_TOKEN);
}));
httpClient.get('/error').subscribe();
const req = httpMock.expectOne('/error');
req.error(new ErrorEvent('Captcha Error'), {
status: 400,
statusText: 'Captcha-Error',
headers: new HttpHeaders().set('Captcha-Status', 'required')
});
tick(200);
}));
});https://stackoverflow.com/questions/52275410
复制相似问题