Angular-为每个请求设置标题


334

对于每个后续请求,我需要在用户登录后设置一些Authorization标头。


要为特定请求设置标题,

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

参考

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

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



Answers:


379

要回答这个问题,您是否可以提供一种包装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


1
“ this.http = http;”在哪里 来自,我相信我们需要在使用之前声明它?
co2f2e 16-10-7

1
角标题(设置和附加函数)正在“标准化”标题的键并使它变为小写。从Headers.d.ts://“HTTP字符集由大小写不敏感的令牌标识” //规格在tools.ietf.org/html/rfc2616 对于那些谁没有后端是作品的规范; 这是一个绕过的方法:let headersMap = .get(options,'headers._headersMap',new Map()); headersMap.set( '授权',[ .replace(Bearer ${token}/ \“/克, '')]);
sangress

@DiegoUnanue我正在使用Angular 2的最终版本和Thierry的实现工作。只需在导入语句中将“ angular2”替换为“ @angular”即可。
f123

Mark Pieszak-我应该包括HttpClient的提供程序吗?
user3127109 '16

现在TS抛出错误:`类型参数'{headers:Headers; }”不可分配给“ RequestOptionsArgs”类型的参数
elporfirio

142

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<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // 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 {}

我实现了这个功能,当执行ng服务时我可以看到请求标头,但是当执行ng b prod并在tomcat中进行部署时,我看不到标头...使用spring-boot,标头去了哪里?
naoru

1
不知道是否是因为我正在使用Express节点API,但是即使使用正式的Angular文档,它也不适用于我。:/
Maxime Lafarie

错误TypeError:非对象上调用了CreateListFromArrayLike
DAG

1
您如何将任何东西注入HttpInterceptor?
zaitsman '17

我已经实现了相同的功能,但是在PUT和DELETE API中,请求标头对我不起作用。
Pooja '18

78

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 })
]);

每个通话中应包含“ My-Custom-Header”。

更新:

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

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月 我看到很多人都在寻求这种解决方案,但我会建议否则。全局追加标头会将auth令牌发送到从您的应用发出的每个 api调用。因此,前往第三方插件(例如对讲机或zendesk或任何其他api)的api调用也将带有您的授权标头。这可能会导致很大的安全漏洞。因此,相反,请全局使用拦截器,但要手动检查传出的呼叫是否朝向服务器的api端点,然后附加身份验证标头。


1
this.http._defaultOptions.headers.delete('My-Custom-Header')因此,可以通过以下代码this.http._defaultOptions.headers.append('My-New-Custom-Header','newvalue ')
anit

2
@Dinistro是的,现在我不建议自己这样做。由于角度Beta的限制以及我在全局控制身份验证流的习惯,我不得不提出这种解决方法。但是我相信现在github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts有更好更好的解决方案。
anit 2016年

1
使用BaseRequestOptions的问题是它的构造函数在浏览器的应用程序生存期内仅运行一次。因此,如果您想在一段时间内更改标头值(例如csrf_token),则无法采用这种方法(即使此类中的重写合并方法也
无济于事:

1
问题是,如果您使用包装器来直接访问HTTP的第三方库,则需要重新编写才能使用它。我仍然不知道该如何解决。确实需要拦截器。不知道是否有人知道更好的方法。
Piotr Stulinski

6
嗨,在angular4 _defaultOptions受保护,因此不能被
叫停

24

尽管我回答得很晚,但可能会对其他人有所帮助。要将标头注入所有请求@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]
})

4
您需要@Injectable并在类中定义标头,我通过@Injectable()导出类测试成功,Custom类扩展了CustomRequestOptions BaseRequestOptions {headers:Headers = new Headers({'Authorization':'xxx'}); }
EasonBlack

好吧,我在2.0.0中做到了,没有检查2.0.1
EasonBlack '16

重要说明在这里,我遇到了一个问题,CustomRequestOptions即使使用@ Inject / @ Injectable 也无法注入任何东西。我意识到的解决方案是扩展RequestOptions而不是BaseRequestOptions。提供BaseRequestOptions不起作用,但是扩展RequestOptions却使DI再次起作用。
国会

5
此解决方案很简单,但是如果用户将注销并重新登录并且其令牌更改-将不再起作用,因为Authorization标头仅在应用程序初始化上设置一次。
亚历克斯·帕拉蒙诺夫

是的,正确@AlexeyVParamonov。仅当令牌设置一次时,此功能才有用。否则,我们将像您所说的那样编写拦截器。
Shashank Agrawal

15

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<Response> {
    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在整个应用程序中正常使用。


由于我能够将网址过滤到api服务器,并且仅将Auth令牌添加到对其进行的调用中,因此该答案对我来说效果最好。我将请求更改为:request(url:string | Request,options ?: RequestOptionsArgs):Observable <Response> {var _url:string = url.toString(); 如果(_url.indexOf('api.myserver.com')> -1){选项= this._setCustomHeaders(选项); } return super.request(url,options)}
克里斯·霍尔科姆

就我而言,withCredentials和Headers是从request方法的url参数中获取的。我更改了这样的代码:request(url:string | Request,options ?: RequestOptionsArgs):Observable <Response> {options = this._setCustomHeaders(options); if(typeof(url)===“对象”){(<Request> url).withCredentials = options.withCredentials; (<Request> url).headers = options.headers; } return super.request(url,options)}
Argnist

request()您正在重载的方法具有两个调用签名,并且options仅当url指定为字符串时才使用该属性。如果url是的实例Request,则该options属性将被忽略。这可能导致难以捕获的错误。请参阅我的答案以获取更多详细信息。
Slava Fomin II

请注意,此解决方案在服务器平台方面存在一些问题。但是有一些解决方法可以避免这种情况。
Alireza Mirian

这对我一直有效,直到有角度4.2。4.3具有拦截器。
cabaji99

12

通过扩展Angular 2 HttpProvider 创建一个自定义Http类,constructorrequest在自定义Http类中简单地覆盖and 方法。下面的示例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<Response> {
    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/


这种方法非常适合使用替代类提供程序。您可以使用“ provide:Http”代替通常在模块中使用的“ provide:HttpService”,而可以使用模块中的“ provide:HttpService”。
吉尔伯特·阿里纳斯·匕首2016年

如何向此扩展的http类添加其他属性?例如,路由器:路由器或任何自定义可注入服务。
shafeequemat

@shafeequemat您不能使用此功能。您可以在自定义http类中定义另一个方法,例如setRouter(router)。或者,您可以创建另一个类,然后在其中注入自定义的http类,而不是相反。
Adones Pitogo

9

对于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<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    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<any>) => {
      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 {
}

8

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

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

小更新:有更好的表现,你可以考虑把所有的静态标题(如“内容类型”),以构造
АлександрИльинский

7

这是我为每个请求设置令牌的方式。

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

6

这是已接受答案的改进版本,已针对Angular2 final更新:

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

        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());
    }
}

当然,应该将其扩展为诸如deleteput如果需要的方法(在我的项目中,我现在还不需要它们)。

其优点是,有在少重复的代码get/ post/ ...方法。

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


您如何让tslint忽略标头?
Winnemucca

5

如何像下面这样保持单独的服务

            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);

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

在此处输入图片说明


5

经过一番调查,我发现最终也是最简单的方法是扩展BaseRequestOptions我喜欢的方法。
以下是由于某些原因我尝试放弃的方法:
1.扩展BaseRequestOptions并在中添加动态标头constructor()。如果我登录,它将无法正常工作。它将创建一次。因此它不是动态的。
2.延伸Http。与上述相同的原因,我无法在中添加动态标头constructor()。如果我重写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()将为每个请求调用此函数。


在给出的所有答案中,这是引起我注意的答案,因为我已经寻求了基于extended的解决方案BaseRequestOptions。但是,可悲的是,这对我没有用。任何可能的原因?
vigamage '17

使它工作。这个解决方案很好,我的服务器有问题。我必须对CORS飞行前请求进行一些配置。请参阅此链接 stackoverflow.com/a/43962690/3892439
vigamage '17

您如何绑定AuthRequestOptions到应用程序的其余部分?我尝试将其放在本providers节中,但是它什么也没做。
特拉维斯公园

您必须覆盖而RequestOptions不是的提供程序BaseRequestOptionsangular.io/api/http/BaseRequestOptions
特拉维斯公园

在我的应用程序中,我只扩展了BaseRequestOptions,它已经扩展了RequestOptions。然后在app.module中,应设置提供者:{ provide: RequestOptions, useClass: AuthRequestOptions }
Mavlarn

5

尽管我回答得很晚,但是如果有人正在寻求更简单的解决方案。

我们可以使用angular2-jwt。从Angular 2应用发出HTTP请求时,angular2-jwt可自动将JSON Web令牌(JWT)附加为Authorization标头。

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

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')
    );
}

将有助于转到github.com/auth0/angular2-jwt#installation和使用他们的安装指南适应这个答案
Zuriel

4

我喜欢覆盖默认选项的想法,这似乎是一个不错的解决方案。

但是,如果您打算扩展Http课程。请务必通读!

这里的一些答案实际上显示了request()方法的不正确重载,这可能导致难以捕获的错误和奇怪的行为。我自己偶然发现了这个。

此解决方案基于request()Angular中的方法实现4.2.x,但应与将来兼容:

import {Observable} from 'rxjs/Observable';
import {Injectable} from '@angular/core';

import {
  ConnectionBackend, Headers,
  Http as NgHttp,
  Request,
  RequestOptions,
  RequestOptionsArgs,
  Response,
  XHRBackend
} from '@angular/http';


import {AuthenticationStateService} from '../authentication/authentication-state.service';


@Injectable()
export class Http extends NgHttp {

  constructor (
    backend: ConnectionBackend,
    defaultOptions: RequestOptions,
    private authenticationStateService: AuthenticationStateService
  ) {
    super(backend, defaultOptions);
  }


  request (url: string | Request, options?: RequestOptionsArgs): Observable<Response> {

    if ('string' === typeof url) {

      url = this.rewriteUrl(url);
      options = (options || new RequestOptions());
      options.headers = this.updateHeaders(options.headers);

      return super.request(url, options);

    } else if (url instanceof Request) {

      const request = url;
      request.url = this.rewriteUrl(request.url);
      request.headers = this.updateHeaders(request.headers);

      return super.request(request);

    } else {
      throw new Error('First argument must be a url string or Request instance');
    }

  }


  private rewriteUrl (url: string) {
    return environment.backendBaseUrl + url;
  }

  private updateHeaders (headers?: Headers) {

    headers = headers || new Headers();

    // Authenticating the request.
    if (this.authenticationStateService.isAuthenticated() && !headers.has('Authorization')) {
      headers.append('Authorization', 'Bearer ' + this.authenticationStateService.getToken());
    }

    return headers;

  }

}

请注意,我以这种方式导入原始类import { Http as NgHttp } from '@angular/http';,以防止名称冲突。

此处解决的问题是该request()方法具有两个不同的调用签名。当Request传递object而不是URL时stringoptionsAngular将忽略该参数。因此,两种情况都必须妥善处理。

这是如何使用DI容器注册此重写的类的示例:

export const httpProvider = {
  provide: NgHttp,
  useFactory: httpFactory,
  deps: [XHRBackend, RequestOptions, AuthenticationStateService]
};


export function httpFactory (
  xhrBackend: XHRBackend,
  requestOptions: RequestOptions,
  authenticationStateService: AuthenticationStateService
): Http {
  return new Http(
    xhrBackend,
    requestOptions,
    authenticationStateService
  );
}

通过这种方法,您可以Http正常地注入类,但是您替代的类将被神奇地注入。这使您可以轻松集成解决方案,而无需更改应用程序的其他部分(实际中的多态性)。

只需添加httpProviderproviders模块元数据的属性即可。


1

最简单的

建立config.ts档案

import { HttpHeaders } from '@angular/common/http';

export class Config {
    url: string = 'http://localhost:3000';
    httpOptions: any = {
        headers: new HttpHeaders({
           'Content-Type': 'application/json',
           'Authorization': JSON.parse(localStorage.getItem('currentUser')).token
        })
    }
}

然后在上service,只需导入config.ts文件

import { Config } from '../config';
import { HttpClient } from '@angular/common/http';

@Injectable()
export class OrganizationService {
  config = new Config;

  constructor(
    private http: HttpClient
  ) { }

  addData(data): Observable<any> {
     let sendAddLink = `${this.config.url}/api/addData`;

     return this.http.post(sendAddLink , data, this.config.httpOptions).pipe(
       tap(snap => {
      return snap;
        })
    );
 } 

我认为这是最简单和最安全的。


0

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

不起作用,我自己尝试过。除了刷新之外,不会调用其他任何东西。
菲尔(Phil)

0

我可以选择一个更简单的解决方案>通过您的api get(或其他)函数将新的Headers添加到默认选项中,以进行合并或加载。

get(endpoint: string, params?: any, options?: RequestOptions) {
  if (!options) {
    options = new RequestOptions();
    options.headers = new Headers( { "Accept": "application/json" } ); <<<<
  }
  // [...] 
}

当然,您可以在默认选项或班级中的任何情况下将此标头外部化。这是在Ionic生成的api.ts @Injectable()导出类API {}中

它非常快速,对我有用。我不想要json / ld格式。


-4

您可以canActive在路线中使用,如下所示:

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { CanActivate } from '@angular/router';
import { AuthService } from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private auth: AuthService, private router: Router) {}

  canActivate() {
    // If user is not logged in we'll send them to the homepage 
    if (!this.auth.loggedIn()) {
      this.router.navigate(['']);
      return false;
    }
    return true;
  }

}

const appRoutes: Routes = [
  {
    path: '', redirectTo: '/deals', pathMatch: 'full'
  },
  {
    path: 'special',
    component: PrivateDealsComponent,
    /* We'll use the canActivate API and pass in our AuthGuard.
       Now any time the /special route is hit, the AuthGuard will run
       first to make sure the user is logged in before activating and
       loading this route. */
    canActivate: [AuthGuard]
  }
];

摘自:https : //auth0.com/blog/angular-2-authentication

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.