首页 > 解决方案 > 如何将动态变量从服务传递给 http_interceptor

问题描述

我有多个角度项目,每个项目都有一个调用相同 API 的服务。我一直在向请求添加一个标头,以确定从哪个应用程序发送了请求。所以我一直在尝试创建一个具有基本服务类的库来设置标头值


    @Injectable({ providedIn: "root" })
    export class AppbaseService {
        scope: string; 
        constructor(@Inject(forwardRef(()=>'scope')) scope:string) { 
            this.scope = scope;
        }
        getScope():string{
            return this.scope;
        }
    }

和一个http 拦截器,用于将该动态值作为标头附加到请求中


    @Injectable()
    export class ScopeInterceptor implements HttpInterceptor {
    
        constructor(private appBaseService: AppbaseService) {
        }
    
        intercept(req: HttpRequest<any>,
            next: HttpHandler): Observable<HttpEvent<any>> {
    
            const clonedRequest = req.clone({
                headers: req.headers.append(
                    'Scope',
                    this.appBaseService.scope
                )
            });
            return next.handle(clonedRequest);
        }
    }

最后是一个将动态值设置为提供者的工厂


    export function appValueFactory(baseService: AppbaseService) {
        console.log(baseService);
        return baseService.getScope();
    }

但我不知道如何在模块中设置提供程序并低于错误,这不是很有帮助。


    Uncaught Error: Can't resolve all parameters for qI: (?).
        at Jt (main.js:1)
        at e._getDependenciesMetadata (main.js:1)
        at e._getFactoryMetadata (main.js:1)
        at e.getProviderMetadata (main.js:1)
        at main.js:1
        at Array.forEach (<anonymous>)
        at e._getProvidersMetadata (main.js:1)
        at main.js:1
        at Array.forEach (<anonymous>)
        at e._getProvidersMetadata (main.js:1)

有人可以指出我正确的方向吗?

谢谢你。

标签: angularangular-http-interceptorsangular-di

解决方案


首先,¿这是为了什么:@Inject(forwardRef(()=>'scope'))?在构造函数中,您应该注入服务并且范围是一个字符串。

我知道scope是当前应用程序的字符串标识符,因此简单的解决方案是直接在拦截器中添加该字符串。

如果您希望使用服务来获取该字符串,问题将在里面AppbaseService,因为值是异步的(它填充在构造函数中)所以,如果您的代码在创建之前scope尝试调用,将是未定义的。ScopeInterceptorAppbaseServicescope

为了解决这个问题,让服务返回一个 Observable(我们假设scopeService.getAppScope()返回这个应用的范围字符串)

    export class AppbaseService {
        scope = new BehaviorSubject<string>('');
        constructor(private scopeService: ScopeService) { 
            this.scope.next(scopeService.getAppScope());
        }
        getScope$(): Observable<string> {
            return this.scope.asObservable();
        }
    }

并且从拦截器使用这个异步函数并返回一个 Observable:

        intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
            return this.appBaseService.getScope$().pipe(
              filter(scope => !!scope), 
              take(1), 
              switchMap(scope => {
                const clonedRequest = req.clone({
                  headers: req.headers.append('Scope',scope)
                });
                return next.handle(clonedRequest);
            }))
        }

rxjs函数说明:

  • 用于过滤未定义的filter值:当范围尚未定义时,不要继续使用管道。
  • take(1):一旦收到值,只消费一次可观察对象然后完成。
  • switchMap: 从范围 observable 中获取值并返回另一个 observableHttpEvent

推荐阅读