Angular - Set headers for every request

前端 未结 19 1598
[愿得一人]
[愿得一人] 2020-11-22 07:43

I need to set some Authorization headers after the user has logged in, for every subsequent request.


To set headers for a particular request,



        
19条回答
  •  囚心锁ツ
    2020-11-22 08:27

    I like the idea to override default options, this seems like a good solution.

    However, if you are up to extending the Http class. Make sure to read this through!

    Some answers here are actually showing incorrect overloading of request() method, which could lead to a hard-to-catch errors and weird behavior. I've stumbled upon this myself.

    This solution is based on request() method implementation in Angular 4.2.x, but should be future-compatible:

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

    Notice that I'm importing original class this way import { Http as NgHttp } from '@angular/http'; in order to prevent name clashes.

    The problem addressed here is that request() method has two different call signatures. When Request object is passed instead of the URL string, the options argument is ignored by Angular. So both cases must be properly handled.

    And here's the example of how to register this overridden class with DI container:

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

    With such approach you can inject Http class normally, but your overridden class will be magically injected instead. This allows you to integrate your solution easily without changing other parts of the application (polymorphism in action).

    Just add httpProvider to the providers property of your module metadata.

提交回复
热议问题