【问题标题】:Conditional interceptor action upon request parameter in AngularAngular中请求参数的条件拦截器操作
【发布时间】:2020-10-02 03:45:07
【问题描述】:

我需要在发送请求之前根据我的初始意图有条件地在 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 的配置参数中传递任何参数 - 不起作用。它只接受某些参数。
  2. 与后端协商以传递-返回某些内容(如标头或参数) - 在我们变得依赖后端时打破前端的分离;
  3. 使用装饰器/扩展 HttpClient 组件,这样我就可以传递我的参数 - 可以,但我正在寻找本机解决方案。

提前谢谢你!

【问题讨论】:

  • Oleksandr 建议的使用装饰器方法的详细实现。可能对登陆这里的人有用。 medium.com/@abidhmuhsin/… 一开始很困惑,但最终探索了这个话题并为我自己写了一个。这是代码更改最少的最佳方式。谢谢Oleksandr。
  • 哇,精彩的作品!谢谢,@Abi.z

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


【解决方案1】:

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

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

    ignoreNextOrder(){
        this.ignore = true;
    }

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

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

【讨论】:

  • 并没有真正回答这个问题,但我给了你一个 +1,因为这是我采用的解决方案,因为它正是我正在寻找这个问题的原因。
【解决方案2】:

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

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

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 '';
    }
}

【讨论】:

    【解决方案3】:

    不推荐前两种方法。

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

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

    您应该创建一个装饰器,该装饰器只应在您需要显示加载器时使用。这样别人就更容易理解了。逻辑也不依赖于后端。

    【讨论】:

      【解决方案4】:

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

      ...或...

      我在我的一个项目中使用@LoaderTrigger 装饰器来启动加载器,我没有为此使用拦截器。您所需要的只是装饰一个返回 observable 的方法或函数并实现 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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        相关资源
        最近更新 更多