我需要在用户登录后为每个后续请求设置一些授权头。
为特定请求设置头信息,
import {Headers} from 'angular2/http';
var headers = new Headers();
headers.append(headerName, value);
// HTTP POST using these headers
this.http.post(url, data, {
headers: headers
})
// do something with the response
参考
但是,以这种方式为每个请求手动设置请求头是不可行的。
我如何设置头设置一旦用户登录,也删除注销这些头?
从Angular 4.3开始,HTTP拦截器现在可以通过新的HttpClient @angular/common/ HTTP使用了。X版本及更高版本。
现在为每个请求添加头文件非常简单:
import {
HttpEvent,
HttpInterceptor,
HttpHandler,
HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { Injectable } from '@angular/core';
@Injectable()
export class AddHeaderInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// Clone the request to add the new header
const clonedRequest = req.clone({ headers: req.headers.append('Authorization', 'Bearer 123') });
// Pass the cloned request instead of the original request to the next handle
return next.handle(clonedRequest);
}
}
有一个不可变性的原则,这就是为什么在设置新内容之前需要克隆请求。
由于编辑头部是一个非常常见的任务,实际上有一个快捷方式(在克隆请求时):
const clonedRequest = req.clone({ setHeaders: { Authorization: 'Bearer 123' } });
创建拦截器之后,你应该使用HTTP_INTERCEPTORS提供的方法注册它。
import { HTTP_INTERCEPTORS } from '@angular/common/http';
@NgModule({
providers: [{
provide: HTTP_INTERCEPTORS,
useClass: AddHeaderInterceptor,
multi: true,
}],
})
export class AppModule {}
这就是我如何为每个请求设置令牌。
import { RequestOptions, BaseRequestOptions, RequestOptionsArgs } from '@angular/http';
export class CustomRequestOptions extends BaseRequestOptions {
constructor() {
super();
this.headers.set('Content-Type', 'application/json');
}
merge(options?: RequestOptionsArgs): RequestOptions {
const token = localStorage.getItem('token');
const newOptions = super.merge(options);
if (token) {
newOptions.headers.set('Authorization', `Bearer ${token}`);
}
return newOptions;
}
}
并在app.module.ts中注册
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule
],
providers: [
{ provide: RequestOptions, useClass: CustomRequestOptions }
],
bootstrap: [AppComponent]
})
export class AppModule { }
经过一些调查,我发现最后也是最简单的方法是扩展我喜欢的BaseRequestOptions。
以下是我尝试过但由于某些原因放弃的方法:
1. 扩展BaseRequestOptions,并在constructor()中添加动态头。如果我登录,它不能工作。它只创建一次。所以它不是动态的。
2. 扩展Http。与上面的原因相同,我不能在构造函数()中添加动态头文件。如果我重写request(..)方法,并设置报头,像这样:
request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
let token = localStorage.getItem(AppConstants.tokenName);
if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
if (!options) {
options = new RequestOptions({});
}
options.headers.set('Authorization', 'token_value');
} else {
url.headers.set('Authorization', 'token_value');
}
return super.request(url, options).catch(this.catchAuthError(this));
}
你只需要重写这个方法,而不是重写所有的get/post/put方法。
3.我的首选解决方案是扩展BaseRequestOptions和覆盖merge():
@Injectable()
export class AuthRequestOptions extends BaseRequestOptions {
merge(options?: RequestOptionsArgs): RequestOptions {
var newOptions = super.merge(options);
let token = localStorage.getItem(AppConstants.tokenName);
newOptions.headers.set(AppConstants.authHeaderName, token);
return newOptions;
}
}
这个merge()函数将被每个请求调用。
迟到总比不到好……=)
您可以采用扩展BaseRequestOptions的概念(从这里https://angular.io/docs/ts/latest/guide/server-communication.html#!#override-default-request-options)并“动态”刷新头(不仅仅是在构造函数中)。你可以像这样使用getter/setter重写“headers”属性:
import { Injectable } from '@angular/core';
import { BaseRequestOptions, RequestOptions, Headers } from '@angular/http';
@Injectable()
export class DefaultRequestOptions extends BaseRequestOptions {
private superHeaders: Headers;
get headers() {
// Set the default 'Content-Type' header
this.superHeaders.set('Content-Type', 'application/json');
const token = localStorage.getItem('authToken');
if(token) {
this.superHeaders.set('Authorization', `Bearer ${token}`);
} else {
this.superHeaders.delete('Authorization');
}
return this.superHeaders;
}
set headers(headers: Headers) {
this.superHeaders = headers;
}
constructor() {
super();
}
}
export const requestOptionsProvider = { provide: RequestOptions, useClass: DefaultRequestOptions };
你可以用一些授权头创建你自己的http客户端:
import {Injectable} from '@angular/core';
import {HttpClient, HttpHeaders} from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class HttpClientWithAuthorization {
constructor(private http: HttpClient) {}
createAuthorizationHeader(bearerToken: string): HttpHeaders {
const headerDict = {
Authorization: 'Bearer ' + bearerToken,
}
return new HttpHeaders(headerDict);
}
get<T>(url, bearerToken) {
this.createAuthorizationHeader(bearerToken);
return this.http.get<T>(url, {
headers: this.createAuthorizationHeader(bearerToken)
});
}
post<T>(url, bearerToken, data) {
this.createAuthorizationHeader(bearerToken);
return this.http.post<T>(url, data, {
headers: this.createAuthorizationHeader(bearerToken)
});
}
}
然后在你的服务类中注入它而不是HttpClient:
@Injectable({
providedIn: 'root'
})
export class SomeService {
constructor(readonly httpClientWithAuthorization: HttpClientWithAuthorization) {}
getSomething(): Observable<Object> {
return this.httpClientWithAuthorization.get<Object>(url,'someBearer');
}
postSomething(data) {
return this.httpClientWithAuthorization.post<Object>(url,'someBearer', data);
}
}
angular 2.0.1及更高版本有一些改动:
import {RequestOptions, RequestMethod, Headers} from '@angular/http';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { AppRoutingModule } from './app.routing.module';
import { AppComponent } from './app.component';
//you can move this class to a better place
class GlobalHttpOptions extends RequestOptions {
constructor() {
super({
method: RequestMethod.Get,
headers: new Headers({
'MyHeader': 'MyHeaderValue',
})
});
}
}
@NgModule({
imports: [ BrowserModule, HttpModule, AppRoutingModule ],
declarations: [ AppComponent],
bootstrap: [ AppComponent ],
providers: [ { provide: RequestOptions, useClass: GlobalHttpOptions} ]
})
export class AppModule { }