拦截器仅用于特定服务

时间:2017-09-09 12:34:38

标签: angular4-httpclient

我的应用中有几个服务指向不同的API网址。现在我需要为每个服务设置不同的标头。我的问题是关于Angular 4中的新拦截器。是否有可能为特定服务设置一个拦截器?所以每个服务都有其特定的拦截器?

希望你们能得到我的问题。

4 个答案:

答案 0 :(得分:6)

TL:DR答案:

没有办法。拦截器旨在拦截所有请求。

长答案:

存储库或请求不应该知道它可以通过它的拦截器。因此,我不同意标记请求或检查特定课程的解决方案。

我更喜欢这里提供的解决方案: Example Angular HttpInterceptors

基本上,如果应添加特定标头,您的拦截器必须检查服务(中介模式)。

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    console.log(JSON.stringify(req));

    const token: string = this.currentUserService.token;

    if (token) {
        req = req.clone({ headers: req.headers.set('Authorization', 'Bearer ' + token) });
    }

    if (!req.headers.has('Content-Type')) {
        req = req.clone({ headers: req.headers.set('Content-Type', 'application/json') });
    }

    req = req.clone({ headers: req.headers.set('Accept', 'application/json') });
    return next.handle(req);
}

这是一个很好的例子,但要注意它违反了单一责任原则(设置多个标题)。

除此之外,我认为拦截器是你问题的错误模式。此外,我没有看到拦截器作为向请求添加承载令牌的解决方案。那是我的用例,它把我带到了这里。

基本上我会挑战您的架构并重新思考如何创建请求。这个问题的解决方案可能是设计:

<强>摘要存储库

具有返回HttpRequest的get / post / put等基本方法。

有一个名为&#34;发送&#34;的方法它接受HttpRequest作为参数。

<强>水泥混凝土的存储库

从抽象存储库继承并扩展基本请求函数。

因此,对于您的用例,您有一个基本服务,并且每个特定/自定义服务都继承自此特定服务,这扩展了您的请求的行为。

<强>装饰

为了使这个架构更进一步(就像我一样),你可以创建一个打字稿装饰器(在所有情况下都不可能,例如当需要依赖注入时),这扩展了所有修饰函数的行为。例如,添加特定标头。这看起来像这样:

&#13;
&#13;
import { Observable } from 'rxjs/Observable';
import { HttpClient, HttpRequest, HttpEvent } from '@angular/common/http';
import { Injectable } from '@angular/core';

export abstract class BaseRepository<T> {
    constructor(protected client: HttpClient) {

    }

    public createGetRequest(url: string): HttpRequest<T> {
        return new HttpRequest("GET", url);
    }

    public send(request: HttpRequest<T>): Observable<HttpEvent<T>> {
        return this.client.request(request);
    }
}

@Injectable()
export class NormalServiceRepository extends BaseRepository<any> {

    constructor(protected client: HttpClient) {
        super(client);
    }

    public get(url: string): Observable<any> {
        const baseRequest = super.createGetRequest(url);

        baseRequest.headers.set('Content-Type', 'application/json');

        return this.send(baseRequest);
    }
}



@Injectable()
export class AuthServiceRepository extends BaseRepository<any> {

    constructor(protected client: HttpClient) {
        super(client);
    }

    @AcceptsJson()
    @SendsJson()
    @ForwardCredentials()
    public createGetRequest(url: string): HttpRequest<any> {
        return super.createGetRequest(url);
    }

    public get(url: string): Observable<any> {
        const baseRequest = super.createGetRequest(url);
        return this.send(baseRequest);
    }
}
&#13;
&#13;
&#13;

这应该给你一个基本的图片架构的样子。

有关装饰器的更多信息

TypeScript Decorators

Example Implementations

答案 1 :(得分:1)

使用新的HttpClient触发请求/响应后,将调用所有拦截器。您可以做的一件事是标记您的请求,因此您在设计用于处理该请求的拦截器中设置了正确的标头。

答案 2 :(得分:1)

这个问题有点晚了,但这对我们有用。是的,它进入了拦截器,但是一个简单的条件会使它无法执行。

 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // Do not execute interceptor
    if (some condition)
      return next.handle(req);

    // Else.. do your thing and go next...
    // Add headers, modify reqyest, etc..
    return next.handle(req);
  }

答案 3 :(得分:1)

实际上,有一种方法可以为特定服务提供拦截器。请注意重点,因为它实际上不是HttpInterceptor接口的实现。

TL:DR -跳至底部的示例。

HttpClient实际上仅通过所有可能的方法将输入转换为称为HttpRequest的单个结构,然后将其传递给HttpHandler实现。顾名思义,它负责处理HTTP请求。
HttpHandler个实现中,例如 HttpInterceptingHandler (运行拦截器链)或 HttpXhrBackend (通过HttpBackend类继承,此处理程序是最后一个处理程序)实际发送XHR请求)。如果查看the source code of the former class,您会发现它实际上取决于后者(间接地,在HttpBackend令牌下,HttpXhrBackend作为默认实现提供)。因此,就像拦截器一样,Angular通过DI链接处理程序,其中最后一个是执行请求的后端。

您可以做的是在此处理程序链中添加另一个处理程序,最好是第一个处理程序。为此,您将必须定义一个扩展HttpHandler的类,并注入HttpHandler first 实现(首先,我的意思是在{{1}下提供的实现) }令牌),然后在完成后在HttpHandler方法中进行调用。

最后,由于HTTP客户端是Angular服务,因此它可能会在更多服务之间共享,因此您将需要创建自己的实例来避免这种情况。 HttpClient构造函数需要一个handle实例,您可以在其中传递自己的实现。

请参阅我在这种处理程序中处理身份验证的简单示例:

HttpHandler

以及该特定服务中处理程序的用法:

@Injectable()
export class AuthHandler extends HttpHandler {
    constructor(
        private readonly auth: AuthService,  // custom service providing the auth token
        private readonly next: HttpHandler   // injects the "default" handler -> HttpInterceptingHandler
    ) {
        super();
    }

    /** @override */ handle(req: HttpRequest<any>): Observable<HttpEvent<any>> {
        // do whatever you need on the request
        // because of immutability cloning is required
        const clone = req.clone({
            setHeaders: { 'Authorization': 'Bearer ' + auth.getToken() }
        });
        // pass the request to the next handler, eventually ending up in HttpXhrBackend
        return this.next.handle(clone);
    }
}

此代码在Angular 8上对我有用。
我希望这可以帮助其他迷路者寻求解决方案。