Angular 4.3 拦截器未生效

51

我尝试使用新的Angular 4.3拦截器为所有请求设置授权标头,但是它没有起作用。我在拦截器intercept方法中设置了断点,但浏览器没有命中它,所以似乎angular忽略了我的拦截器。请帮忙解决,谢谢。

user.service.ts:

import {Injectable} from '@angular/core';
import 'rxjs/add/operator/map';
import {Observable} from "rxjs";
import {Http} from "@angular/http";

@Injectable()
export class UserService {

  constructor(public http: Http) {
  }

  public getContacts(): Observable<any[]> {
    return this.http.get('/users/contacts').map(contacts => contacts.json());
  }
}

token.interceptor.ts

import {Injectable} from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {AuthService} from "./shared/auth.service";

@Injectable()
export class TokenInterceptor implements HttpInterceptor {
  constructor(public auth: AuthService) {
  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    request = request.clone({
      setHeaders: {
        Authorization: `Bearer ${this.auth.getToken()}`
      }
    });
    return next.handle(request);
  }
}

app.module.ts:

@NgModule({
  ...
  providers: [
    ...
    {provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true}
  ]
})

你会对另一种方法感兴趣,比如通过扩展先前的 http 服务来创建自己的 http 服务。你可以在那里做同样的事情。 - Gaurav Srivastava
3个回答

82

简而言之 确保整个应用程序只有一个HttpClientModule的导入(建议),或为每个导入提供有效的拦截器配置(仅供测试使用)。

请确保在应用程序的不同模块中不要多次导入HttpClientModule。我曾在惰性加载的模块中导入过它。每个导入都会创建一个新的HttpClient副本,并使用其导入所在模块的配置,因此根模块中提供的拦截器将被覆盖。


9
遗憾的是,Angular文档中没有对这个问题做出解释。我在我的SharedModule中引入了HttpClientModule,因此在我的惰性加载模块中拦截器没有被调用。幸运的是,我找到了你的答案,只需在AppModule中声明HttpClientModule,就可以完美地解决问题。 - Olivier Boissé
这让我想到为什么HttpClientModule中没有一个forRoot方法? - user5711008
1
好的,但是如果我在嵌套组件中使用HttpClient,我该如何在那里导入它? - Alex Shchur
@AlexeyShchur 在你的父模块中导出HttpClientModule。 - Michał Chilczuk

76

原因是 - 您使用旧的Http服务而不是在Angular 4.3中引入的新服务HttpClientHttp将被弃用)。此外,在HttpClient中,默认情况下假定JSON响应类型,因此您应省略.map(contacts => contacts.json())

app.module.ts

...
import { HttpClientModule } from '@angular/common/http';

@NgModule({
 imports: [
   HttpClientModule,
   ...
 ],
 providers: [
   ...
   {provide: HTTP_INTERCEPTORS, useClass: TokenInterceptor, multi: true}
 ]
 ...
})

用户.service.ts

...
import {HttpClient} from "@angular/common/http";

@Injectable()
export class UserService {

  constructor(public http: HttpClient) {
  }

  public getContacts(): Observable<any[]> {
    return this.http.get('/users/contacts');
  }
}

2
如果您已经检查过使用了HttpClient服务,并且只导入了HttpClientModule一次,但仍然存在问题,请检查以下内容:
如果您正在使用providedIn: 'root',并且您的服务位于一个模块内。请注意。
@Injectable({
  providedIn: 'root'
})
export class YourService {
    ...
}

确保您没有将服务添加到模块的提供程序数组中。"最初的回答"
@NgModule({
  ...
  providers: [
    YourService, // REMOVE THIS LINE
  ]
})
export class YourModule { }

那将覆盖该服务的拦截器。原始答案:最初的回答。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接