Angular 5中对请求参数的条件拦截器操作

时间:2018-08-17 10:36:09

标签: angular angular5 angular-httpclient angular-http-interceptors

在发送请求之前,我需要根据我的最初意图在Angular的HTTP拦截器中有条件地采取行动。这是一个简单的抽象构成:

HttpClient 发出的请求完全相同(URL,参数等),有两个目的:

  1. 需要显示加载程序的请求(例如页面更改,初始加载等)

    this.http.post(url, data, config = {**someCustomParam**: true});

  2. 请求不显示的内容(例如状态检查,ping等)

    this.http.post(url, data, config = {**someCustomParam**: false});

拦截请求的结果是这样的:

@Injectable()
export class RequestInterceptor implements HttpInterceptor {
  constructor(private injector: Injector) { }

  public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(request).do((event: HttpEvent<any>) => {
      if (event instanceof HttpErrorResponse) {
      }
    }, (err: any) => {
      if(request.someCustomProperty) {
        **// Do somethnig on TRUE**
      } else {
        **// Do somethnig on FALSE**
      }
    });
  }
}

我面临的问题是我无法在请求中传递自定义参数,并且无法在响应到达后再见面。到目前为止,这是我发现的内容:

  1. 有人建议在http.get / http.post的config参数中传递任何参数-不起作用。它仅接受某些参数。
  2. 与后端协商以传递某些内容(例如标头或参数),从而在我们变得依赖后端时打破了前端的分隔;
  3. 使用装饰器/扩展HttpClient组件,因此我可以传递参数-可以使用,但是我正在寻找本机解决方案。

提前谢谢!

4 个答案:

答案 0 :(得分:1)

我认为最正确的方法是注入服务,该服务应负责通过在服务中使用吸气剂来决定是否做某事。

在此示例中,是否修改请求并添加Authorization标头的决定基于注入的isAuthenticated的getter AuthService的值:

export class AuthInterceptorService implements HttpInterceptor {
    constructor(private authService: AuthService) {}

    intercept(req: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>> {
        if (this.authService.isAuthenticated) {
            const authorizationHeader = this.authService.authorizationHeaderValue;
            const modifiedReq = req.clone({ 
                headers: new HttpHeaders().set('Authorization', authorizationHeader)
            });
            return next.handle(modifiedReq);
        }
        else {
            return next.handle(req);
        }
    }
}

这是AuthService

export class AuthService {

    private user: User | null;

    get isAuthenticated(): boolean {
        return this.user != null && !this.user.expired;
    }

    get authorizationHeaderValue(): string {
        if (this.user)
            return `${this.user.token_type} ${this.user.access_token}`;
        else
            return '';
    }
}

答案 1 :(得分:0)

不建议使用前两种方法。

  • 第一种方法。如果要传递自定义参数,然后编写一些自定义逻辑以避免加载程序显示,请设想一种情况,其中触发了2个API,第一个是应该具有加载程序,第二个应该被忽略,现在在处理请求时您可以忽略不需要加载程序的API,但是当响应到来时,您如何区分api是需要被忽略还是用于隐藏加载程序。有两种解决方案,一种是您需要维护一个api点列表,或者您需要在后端放入一些逻辑以在响应中发送标志。
  • 为解决第一个问题,您有第二个解决方案。在这里,您需要在后端API中进行更改。不建议这样做。

最终方法: 我建议您采用第三种方法。

您应该创建一个装饰器,该装饰器仅在需要显示加载程序时才使用。这样,其他任何人都将更容易理解。而且逻辑不会依赖于后端。

答案 2 :(得分:0)

我建议您将自定义参数作为标头添加到请求中,无论如何您都可以在拦截器中检查它并从请求中删除它。这将是最快的解决方案。

...或...

我在我的一个项目中使用@LoaderTrigger装饰器来启动加载器,但没有使用拦截器。您只需要装饰一个返回可观察的方法或函数并实现LoaderManager。所以这是它的样子:

function LoaderTrigger(target, key, descriptor) {

if (descriptor === undefined) {
    descriptor = Object.getOwnPropertyDescriptor(target, key);
}
const originalMethod = descriptor.value;

descriptor.value = function () {
    LoaderManager.onStarted();
    return originalMethod.apply(this, arguments)
        .map((value) => {
            LoaderManager.onLoaded();
            return value;
        })
        .catch((err) => {
            LoaderManager.onLoaded();
            return Observable.throw(err);
        });
};

return descriptor;
}

答案 3 :(得分:0)

作为一种解决方法,我编写了一个在执行http请求之前起作用的代码。

在加载组件的服务上,我添加了防止下一个启动顺序的功能:

    ignoreNextOrder(){
        this.ignore = true;
    }

    start() {
        if (this.ignore){
            this.ignore = false;
            return   
        }
        this.loadingSubject.next(LoadingType.LOADING);
    }

您必须在不想显示加载动画的请求之前手动调用它,以便在进行http调用并且拦截器尝试启动加载动画时,它将被忽略。