返回
HttpInterceptor 循环引用错误:记一场胜利
前端
2024-01-02 14:13:45
使用 HttpInterceptor 的常见场景是实现基于 token 的验证机制。因为,在基于 token 的验证机制中,证明用户身份的 token 需要被附带在每一…
在 Angular 应用中,你会发现 HttpInterceptor 可以从一个请求的发起,一路追溯到它的终结。如果对 HttpInterceptor 的使用稍有不慎,我们就会遇到循环引用。
以这个犯错的代码为例:
// userService.ts
@Injectable({
providedIn: 'root',
})
export class UserService {
constructor(private http: HttpClient) {}
getUserInfo() {
return this.http.get('/user/info');
}
}
// http.interceptor.ts
@Injectable()
export class HttpInterceptor implements HttpInterceptor {
constructor(private userService: UserService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = this.userService.getUserInfo();
const newReq = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`),
});
return next.handle(newReq);
}
}
我们看看这个流程:
- 当
HttpInterceptor
被调用时,它尝试获取userService
。 UserService
尝试使用HttpClient
发送一个请求来获取用户信息。HttpClient
拦截了这个请求,并调用了HttpInterceptor
。
在这个过程中,HttpInterceptor
和 UserService
相互依赖,导致了循环引用。
如何避免循环引用?
解决这一错误的关键在于,分离 HttpInterceptor
和 UserService
的依赖关系。方法很简单:
- 把 HttpInterceptor 从
UserService
中移出,改成在根模块中直接提供。 HttpInterceptor
使用Injector
来获取UserService
,这样就可以避免循环引用。
将 HttpInterceptor
改写如下:
@Injectable()
export class HttpInterceptor implements HttpInterceptor {
constructor(private injector: Injector) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const userService = this.injector.get(UserService);
const token = userService.getUserInfo();
const newReq = req.clone({
headers: req.headers.set('Authorization', `Bearer ${token}`),
});
return next.handle(newReq);
}
}
在对 HttpInterceptor 进行改写后,我们就可以避免出现循环引用的错误了。
从长远来看,我们可以通过遵循一些最佳实践来避免循环引用。例如:
- 在 Angular 应用中,不要在组件、服务和其他注入对象之间创建循环依赖。
- 尽量减少组件、服务和其他注入对象之间的依赖关系。
- 使用依赖注入来管理依赖关系,并使用类型提示来确保依赖关系是显式的。
总的来说,通过理解循环引用的原因和解决方法,我们可以避免在 Angular 应用中遇到这种错误。希望本文对您有所帮助。