【问题标题】:How to pass dynamic variable to http_interceptor from a service如何将动态变量从服务传递给 http_interceptor
【发布时间】:2021-05-20 22:09:19
【问题描述】:

我有多个 Angular 项目,每个项目都有调用相同 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)

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

谢谢。

【问题讨论】:

    标签: angular angular-http-interceptors angular-di


    【解决方案1】:

    首先,¿这是干什么用的:@Inject(forwardRef(()=&gt;'scope'))? 在构造函数中你应该注入服务并且范围是一个字符串。

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

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

    为了解决这个问题,让服务返回一个 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):一旦收到值,只消费一次observable然后完成。
    • switchMap:从范围 observable 中获取值并返回另一个带有 HttpEvent 的 observable

    【讨论】:

    • 感谢@adrisons 的回复。
    • 我试图使用字符串范围参数作为注入令牌,但显然它适用于静态变量注入。循环依赖也是另一个问题。不幸的是,静态地将应用程序范围添加到拦截器对我来说不是一个选项,因为我想对所有应用程序中的所有服务使用相同的拦截器(来自库)。我想我应该尝试一下你的其他建议。这是我尝试的第一件事,但我认为我错过了异步点构造函数设置值,所以我没有定义。我会尽快尝试并告诉你。再次感谢。
    猜你喜欢
    • 2014-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-07
    • 1970-01-01
    • 2015-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多