当前位置:  开发笔记 > 编程语言 > 正文

Angular - 为每个请求设置标头

如何解决《Angular-为每个请求设置标头》经验,为你挑选了13个好方法。

我需要在用户登录后为每个后续请求设置一些授权标头.


要为特定请求设置标头,

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

参考

但是以这种方式为每个请求手动设置请求标头是不可行的.

如何在用户登录后设置标头集,并在注销时删除这些标头?



1> Thierry Temp..:

要回答,您质疑您可以提供Http从Angular 包装原始对象的服务.如下所述的东西.

import {Injectable} from '@angular/core';
import {Http, Headers} from '@angular/http';

@Injectable()
export class HttpClient {

  constructor(private http: Http) {}

  createAuthorizationHeader(headers: Headers) {
    headers.append('Authorization', 'Basic ' +
      btoa('username:password')); 
  }

  get(url) {
    let headers = new Headers();
    this.createAuthorizationHeader(headers);
    return this.http.get(url, {
      headers: headers
    });
  }

  post(url, data) {
    let headers = new Headers();
    this.createAuthorizationHeader(headers);
    return this.http.post(url, data, {
      headers: headers
    });
  }
}

而不是注入Http对象,你可以注入这一个(HttpClient).

import { HttpClient } from './http-client';

export class MyComponent {
  // Notice we inject "our" HttpClient here, naming it Http so it's easier
  constructor(http: HttpClient) {
    this.http = httpClient;
  }

  handleSomething() {
    this.http.post(url, data).subscribe(result => {
        // console.log( result );
    });
  }
}

我还认为可以使用多个提供程序为Http类提供一些东西,方法是提供自己的类来扩展Http一个...查看此链接:http://blog.thoughtram.io/angular2/2015/11/23/multi-providers -in-angular-2.html.



2> Edmundo Rodr..:

HTTP拦截器现在可通过新HttpClient@angular/common/http,为的角版本4.3.x和超越.

现在为每个请求添加标头非常简单:

import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';

export class AddHeaderInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest, next: HttpHandler): Observable> {
    // Clone the request to add the new header
    const clonedRequest = req.clone({ headers: req.headers.set('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 {}



3> anit..:

BaseRequestOptions在这种情况下,扩展可能会有很大帮助.查看以下代码:

import {provide} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS, Headers, Http, BaseRequestOptions} from 'angular2/http';

import {AppCmp} from './components/app/app';


class MyRequestOptions extends BaseRequestOptions {
  constructor () {
    super();
    this.headers.append('My-Custom-Header','MyCustomHeaderValue');
  }
} 

bootstrap(AppCmp, [
  ROUTER_PROVIDERS,
  HTTP_PROVIDERS,
  provide(RequestOptions, { useClass: MyRequestOptions })
]);

这应包括每次通话中的"我的自定义标题".

更新:

为了能够随时更改标题而不是上面的代码,您还可以使用以下代码添加新标题:

this.http._defaultOptions.headers.append('Authorization', 'token');

删除你可以做

this.http._defaultOptions.headers.delete('Authorization');

还有另一个函数可用于设置值:

this.http._defaultOptions.headers.set('Authorization', 'token');

上述解决方案在打字稿上下文中仍然不完全有效._defaultHeaders受到保护,不应该像这样使用.我建议使用上面的解决方案进行快速修复,但从长远来看,最好在http调用周围编写自己的包装器,它也会处理auth.从auth0获取以下示例,该示例更好,更干净.

https://github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts

更新 - 2018年6月 我看到很多人都在寻求这个解决方案,但我会建议不这样做.全局追加标头会向您的应用发出的每个 api呼叫发送身份验证令牌.因此api调用第三方插件如内部通信或zendesk或任何其他api也将带有您的授权标头.这可能会导致严重的安全漏洞.所以相反,全局使用拦截器,但是如果传出呼叫是否朝向服务器的api端点,则手动检查,然后附加auth头.


嗨,在angular4``defaultOptions`受到保护,因此无法从服务中调用
@Dinistro是的,现在我不推荐自己这样做.我不得不想出这个解决方法,因为角度β限制以及我在全球范围内控制auth流的习惯.但我相信现在https://github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts有一个更好,更干净的解决方案.

4> Shashank Agr..:

虽然我很晚才回答它,但它可能对其他人有所帮助.要在@NgModule使用时为所有请求注入标头,可以执行以下操作:

(我在Angular 2.0.1中对此进行了测试)

/**
 * Extending BaseRequestOptions to inject common headers to all requests.
 */
class CustomRequestOptions extends BaseRequestOptions {
    constructor() {
        super();
        this.headers.append('Authorization', 'my-token');
        this.headers.append('foo', 'bar');
    }
}

现在@NgModule执行以下操作:

@NgModule({
    declarations: [FooComponent],
    imports     : [

        // Angular modules
        BrowserModule,
        HttpModule,         // This is required

        /* other modules */
    ],
    providers   : [
        {provide: LocationStrategy, useClass: HashLocationStrategy},
        // This is the main part. We are telling Angular to provide an instance of
        // CustomRequestOptions whenever someone injects RequestOptions
        {provide: RequestOptions, useClass: CustomRequestOptions}
    ],
    bootstrap   : [AppComponent]
})


这个解决方案很简单,但如果用户将注销并重新登录并更改其令牌 - 它将不再起作用,因为`Authorization`标头仅在应用程序初始化时设置一次.
你需要@Injectable并在类中定义头文件,我通过@Injectable()测试成功导出类CustomRequestOptions扩展BaseRequestOptions {headers:Headers = new Headers({'Authorization':'xxx'}); }

5> jonnie..:

Angular 2.1.2我通过扩展角度Http接近这个:

import {Injectable} from "@angular/core";
import {Http, Headers, RequestOptionsArgs, Request, Response, ConnectionBackend, RequestOptions} from "@angular/http";
import {Observable} from 'rxjs/Observable';

@Injectable()
export class HttpClient extends Http {

  constructor(protected _backend: ConnectionBackend, protected _defaultOptions: RequestOptions) {

    super(_backend, _defaultOptions);
  }

  _setCustomHeaders(options?: RequestOptionsArgs):RequestOptionsArgs{
    if(!options) {
      options = new RequestOptions({});
    }
    if(localStorage.getItem("id_token")) {

      if (!options.headers) {

        options.headers = new Headers();


      }
      options.headers.set("Authorization", localStorage.getItem("id_token"))
    }
    return options;
  }


  request(url: string|Request, options?: RequestOptionsArgs): Observable {
    options = this._setCustomHeaders(options);
    return super.request(url, options)
  }
}

然后在我的应用程序提供商中我能够使用自定义工厂提供'Http'

import { RequestOptions, Http, XHRBackend} from '@angular/http';
import {HttpClient} from './httpClient';
import { RequestOptions, Http, XHRBackend} from '@angular/http';
import {HttpClient} from './httpClient';//above snippet

function httpClientFactory(xhrBackend: XHRBackend, requestOptions: RequestOptions): Http {
  return new HttpClient(xhrBackend, requestOptions);
}

@NgModule({
  imports:[
    FormsModule,
    BrowserModule,
  ],
  declarations: APP_DECLARATIONS,
  bootstrap:[AppComponent],
  providers:[
     { provide: Http, useFactory: httpClientFactory, deps: [XHRBackend, RequestOptions]}
  ],
})
export class AppModule {
  constructor(){

  }
}

现在我不需要声明每个Http方法,并且可以http在我的应用程序中正常使用.



6> Adones Pitog..:

通过扩展Angular 2 HttpProvider 创建一个自定义Http类,并简单地覆盖自定义Http类中的constructorand request方法.以下示例Authorization在每个http请求中添加标头.

import {Injectable} from '@angular/core';
import {Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class HttpService extends Http {

  constructor (backend: XHRBackend, options: RequestOptions) {
    let token = localStorage.getItem('auth_token'); // your custom token getter function here
    options.headers.set('Authorization', `Bearer ${token}`);
    super(backend, options);
  }

  request(url: string|Request, options?: RequestOptionsArgs): Observable {
    let token = localStorage.getItem('auth_token');
    if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
      if (!options) {
        // let's make option object
        options = {headers: new Headers()};
      }
      options.headers.set('Authorization', `Bearer ${token}`);
    } else {
    // we have to add the token to the url object
      url.headers.set('Authorization', `Bearer ${token}`);
    }
    return super.request(url, options).catch(this.catchAuthError(this));
  }

  private catchAuthError (self: HttpService) {
    // we have to pass HttpService's own instance here as `self`
    return (res: Response) => {
      console.log(res);
      if (res.status === 401 || res.status === 403) {
        // if not authenticated
        console.log(res);
      }
      return Observable.throw(res);
    };
  }
}

然后配置main app.module.ts以提供XHRBackend作为ConnectionBackend提供者和RequestOptions自定义Http类:

import { HttpModule, RequestOptions, XHRBackend } from '@angular/http';
import { HttpService } from './services/http.service';
...
@NgModule({
  imports: [..],
  providers: [
    {
      provide: HttpService,
      useFactory: (backend: XHRBackend, options: RequestOptions) => {
        return new HttpService(backend, options);
      },
      deps: [XHRBackend, RequestOptions]
    }
  ],
  bootstrap: [ AppComponent ]
})

之后,您现在可以在服务中使用自定义http提供程序.例如:

import { Injectable }     from '@angular/core';
import {HttpService} from './http.service';

@Injectable()
class UserService {
  constructor (private http: HttpService) {}

  // token will added automatically to get request header
  getUser (id: number) {
    return this.http.get(`/users/${id}`).map((res) => {
      return res.json();
    } );
  }
}

这是一本全面的指南 - http://adonespitogo.com/articles/angular-2-extending-http-provider/



7> Александр Ил..:

迟到总比没好...... =)

您可以采用扩展的概念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 };



8> Prachi..:

对于Angular 5及更高版本,我们可以使用HttpInterceptor来泛化请求和响应操作.这有助于我们避免重复:

1)通用标题

2)指定响应类型

3)查询请求

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';

@Injectable()
export class AuthHttpInterceptor implements HttpInterceptor {

  requestCounter: number = 0;
  constructor() {
  }

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

    request = request.clone({
      responseType: 'json',
      setHeaders: {
        Authorization: `Bearer token_value`,
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
      }
    });

    return next.handle(request).do((event: HttpEvent) => {
      if (event instanceof HttpResponse) {
        // do stuff with response if you want
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        // do stuff with response error if you want
      }
    });
  }
}

我们可以使用此AuthHttpInterceptor类作为HttpInterceptors的提供者:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app.routing-module';
import { AuthHttpInterceptor } from './services/auth-http.interceptor';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    BrowserAnimationsModule,
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthHttpInterceptor,
      multi: true
    }
  ],
  exports: [],
  bootstrap: [AppComponent]
})
export class AppModule {
}



9> Pierre Henry..:

以下是Angular2最终更新的已接受答案的改进版本:

import {Injectable} from "@angular/core";
import {Http, Headers, Response, Request, BaseRequestOptions, RequestMethod} from "@angular/http";
import {I18nService} from "../lang-picker/i18n.service";
import {Observable} from "rxjs";
@Injectable()
export class HttpClient {

    constructor(private http: Http, private i18n: I18nService ) {}

    get(url:string):Observable {
        return this.request(url, RequestMethod.Get);
    }

    post(url:string, body:any) {   
        return this.request(url, RequestMethod.Post, body);
    }

    private request(url:string, method:RequestMethod, body?:any):Observable{

        let headers = new Headers();
        this.createAcceptLanguageHeader(headers);

        let options = new BaseRequestOptions();
        options.headers = headers;
        options.url = url;
        options.method = method;
        options.body = body;
        options.withCredentials = true;

        let request = new Request(options);

        return this.http.request(request);
    }

    // set the accept-language header using the value from i18n service that holds the language currently selected by the user
    private createAcceptLanguageHeader(headers:Headers) {

        headers.append('Accept-Language', this.i18n.getCurrentLang());
    }
}

当然,它应该扩展到类似的方法delete,put如果需要的话(我现在还不需要它们在我的项目中).

优点是get/ post/ ...方法中的重复代码较少.

请注意,在我的情况下,我使用cookie进行身份验证.我需要i18​​n(Accept-Language标题)的标题,因为我们的API返回的许多值都是用用户的语言翻译的.在我的应用程序中,i18n服务保存用户当前选择的语言.



10> 小智..:

这就是我为每个请求设置令牌的方法.

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 { }



11> co2f2e..:

如何保持单独的服务如下

            import {Injectable} from '@angular/core';
            import {Headers, Http, RequestOptions} from '@angular/http';


            @Injectable()
            export class HttpClientService extends RequestOptions {

                constructor(private requestOptionArgs:RequestOptions) {
                    super();     
                }

                addHeader(headerName: string, headerValue: string ){
                    (this.requestOptionArgs.headers as Headers).set(headerName, headerValue);
                }
            }

当你从另一个地方打电话时使用 this.httpClientService.addHeader("Authorization", "Bearer " + this.tok);

并且您将看到添加的标题,例如: - 授权如下

在此输入图像描述



12> Mavlarn..:

经过一番调查,我发现最后也是最简单的方法就是延伸BaseRequestOptions我喜欢的.
以下是我尝试和放弃的方式:
1.扩展BaseRequestOptions,并添加动态标头constructor().如果我登录,它无法工作.它将被创建一次.所以它不是动态的.
2.延伸Http.与上面相同的原因,我无法添加动态标头constructor().如果我重写request(..)方法,并设置标题,像这样:

request(url: string|Request, options?: RequestOptionsArgs): Observable {
 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()每个请求都会调用此函数.



13> 小智..:

虽然我很晚才回答这个问题,但是如果有人在寻求更简单的解决方案.

我们可以使用angular2-jwt.在从Angular 2应用程序发出HTTP请求时,angular2-jwt可自动将JSON Web令牌(JWT)作为授权标头附加.

我们可以使用高级配置选项设置全局标头

export function authHttpServiceFactory(http: Http, options: RequestOptions) {
  return new AuthHttp(new AuthConfig({
    tokenName: 'token',
        tokenGetter: (() => sessionStorage.getItem('token')),
        globalHeaders: [{'Content-Type':'application/json'}],
    }), http, options);
}

并按请求发送令牌

    getThing() {
  let myHeader = new Headers();
  myHeader.append('Content-Type', 'application/json');

  this.authHttp.get('http://example.com/api/thing', { headers: myHeader })
    .subscribe(
      data => this.thing = data,
      err => console.log(error),
      () => console.log('Request Complete')
    );

  // Pass it after the body in a POST request
  this.authHttp.post('http://example.com/api/thing', 'post body', { headers: myHeader })
    .subscribe(
      data => this.thing = data,
      err => console.log(error),
      () => console.log('Request Complete')
    );
}

推荐阅读
手机用户2502851955
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有