Angular 4.3 拦截器——如何使用?
Angular 4.3 Interceptors - How to use?
我正在构建一个需要授权的新应用 headers。通常,我使用的方法与 scotch.io article 中的方法非常相似。但我注意到 HTTP 拦截器现在通过新的 HttpClientModule 在 Angular 4 生态系统中得到了完全支持,我正试图找到一些关于如何使用它们的文档。
如果我认为(从 4.3 开始)这是注入授权的最佳做法 headers 是不正确的,我也乐于接受建议。我的想法是,这是最近添加的一项功能,这意味着可能有充分的理由迁移到 "Angular Approved" 方法。
这个答案借用了 CodeWarrior 链接到的official documentation。
Angular 允许您创建一个 HttpInterceptor:
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
}
然后您可以像这样将其集成到您的应用程序中:
import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: NoopInterceptor,
multi: true,
}],
})
export class AppModule {}
要添加授权 header,您可以使用更改后的 header 克隆请求:
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
const authHeader = this.auth.getAuthorizationHeader();
// Clone the request to add the new header.
const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
// Pass on the cloned request instead of the original request.
return next.handle(authReq);
}
}
注意拦截器就像一个链条,所以你可以设置多个拦截器来执行不同的任务。
将 AuthService 注入拦截器的构造函数时出现此错误:
Uncaught Error: Provider parse errors: Cannot instantiate cyclic
dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in
NgModule AppModule in ./AppModule@-1:-1
因此,我没有将其注入构造函数,而是使用了 Injector
或 @angular/core
,并且效果很好。我将令牌存储在 localStorage
中并使用基本身份验证。我需要设置
Authorization: 'Bearer token_string'
我是这样实现的:
token.interceptor.ts
import {Injectable, Injector} from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {AuthService} from './auth.service';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(AuthService);
if (auth.getToken()) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${auth.getToken()}`
}
});
}
return next.handle(request);
}
}
AuthService中的getToken函数
在这里您可以实现整个逻辑以获取 header 或仅获取令牌。在我的例子中,我只是调用它来获取 JWT 令牌字符串。
/**
* Get jwt token
* @returns {string}
*/
getToken(): string {
return localStorage.getItem('token');
}
app.module.ts
导入 TokenInterceptor
import {TokenInterceptor} from './pathToTheFile/token.interceptor';
在 providers:
数组的 @NgModule
下添加以下内容。
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
//, other providers
]
我在推荐方法中遇到的问题是,拦截器必须在编译时已知,而且显然都在同一个模块中。
我选择实现一个拦截器和一系列可以在运行时扩展的处理函数。服务的拦截方法负责 next() 逻辑。
服务(基本代码,无验证或维护):
export type HttpHandlerFunction = (req: HttpRequest<any>) => HttpRequest<any>;
@Injectable()
export class HttpInterceptorService implements HttpInterceptor {
private _handlers: Array<HttpHandlerFunction> = [];
addHandler(handler: HttpHandlerFunction): void {
this._handlers.push(handler);
}
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
this._handlers.forEach((handler: HttpHandlerFunction) => {
req = handler(req);
})
return next.handle(req);
}
}
以及在不同模块中的某些服务中的用法:
constructor(injector: Injector) {
const interceptorsArray: Array<any> = injector.get(HTTP_INTERCEPTORS),
interceptor: HttpInterceptorService = interceptorsArray &&
interceptorsArray.filter((i: any) => i instanceof HttpInterceptorService)[0];
if (interceptor) {
interceptor.addHandler((req: HttpRequest<any>) => {
const accessToken = this.getAccessToken();
if (accessToken) {
// doesn't work with direct headers.set, you must clone
req = req.clone({ headers: req.headers.set('Authorization', accessToken) });
}
return req;
});
}
我正在构建一个需要授权的新应用 headers。通常,我使用的方法与 scotch.io article 中的方法非常相似。但我注意到 HTTP 拦截器现在通过新的 HttpClientModule 在 Angular 4 生态系统中得到了完全支持,我正试图找到一些关于如何使用它们的文档。
如果我认为(从 4.3 开始)这是注入授权的最佳做法 headers 是不正确的,我也乐于接受建议。我的想法是,这是最近添加的一项功能,这意味着可能有充分的理由迁移到 "Angular Approved" 方法。
这个答案借用了 CodeWarrior 链接到的official documentation。
Angular 允许您创建一个 HttpInterceptor:
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
@Injectable()
export class NoopInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
return next.handle(req);
}
}
然后您可以像这样将其集成到您的应用程序中:
import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: NoopInterceptor,
multi: true,
}],
})
export class AppModule {}
要添加授权 header,您可以使用更改后的 header 克隆请求:
import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Get the auth header from the service.
const authHeader = this.auth.getAuthorizationHeader();
// Clone the request to add the new header.
const authReq = req.clone({headers: req.headers.set('Authorization', authHeader)});
// Pass on the cloned request instead of the original request.
return next.handle(authReq);
}
}
注意拦截器就像一个链条,所以你可以设置多个拦截器来执行不同的任务。
将 AuthService 注入拦截器的构造函数时出现此错误:
Uncaught Error: Provider parse errors: Cannot instantiate cyclic dependency! InjectionToken_HTTP_INTERCEPTORS ("[ERROR ->]"): in NgModule AppModule in ./AppModule@-1:-1
因此,我没有将其注入构造函数,而是使用了 Injector
或 @angular/core
,并且效果很好。我将令牌存储在 localStorage
中并使用基本身份验证。我需要设置
Authorization: 'Bearer token_string'
我是这样实现的:
token.interceptor.ts
import {Injectable, Injector} from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {AuthService} from './auth.service';
@Injectable()
export class TokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const auth = this.injector.get(AuthService);
if (auth.getToken()) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${auth.getToken()}`
}
});
}
return next.handle(request);
}
}
AuthService中的getToken函数
在这里您可以实现整个逻辑以获取 header 或仅获取令牌。在我的例子中,我只是调用它来获取 JWT 令牌字符串。
/**
* Get jwt token
* @returns {string}
*/
getToken(): string {
return localStorage.getItem('token');
}
app.module.ts
导入 TokenInterceptor
import {TokenInterceptor} from './pathToTheFile/token.interceptor';
在 providers:
数组的 @NgModule
下添加以下内容。
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: TokenInterceptor,
multi: true
}
//, other providers
]
我在推荐方法中遇到的问题是,拦截器必须在编译时已知,而且显然都在同一个模块中。
我选择实现一个拦截器和一系列可以在运行时扩展的处理函数。服务的拦截方法负责 next() 逻辑。
服务(基本代码,无验证或维护):
export type HttpHandlerFunction = (req: HttpRequest<any>) => HttpRequest<any>;
@Injectable()
export class HttpInterceptorService implements HttpInterceptor {
private _handlers: Array<HttpHandlerFunction> = [];
addHandler(handler: HttpHandlerFunction): void {
this._handlers.push(handler);
}
intercept(req: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
this._handlers.forEach((handler: HttpHandlerFunction) => {
req = handler(req);
})
return next.handle(req);
}
}
以及在不同模块中的某些服务中的用法:
constructor(injector: Injector) {
const interceptorsArray: Array<any> = injector.get(HTTP_INTERCEPTORS),
interceptor: HttpInterceptorService = interceptorsArray &&
interceptorsArray.filter((i: any) => i instanceof HttpInterceptorService)[0];
if (interceptor) {
interceptor.addHandler((req: HttpRequest<any>) => {
const accessToken = this.getAccessToken();
if (accessToken) {
// doesn't work with direct headers.set, you must clone
req = req.clone({ headers: req.headers.set('Authorization', accessToken) });
}
return req;
});
}