Angular - Tetapkan tajuk untuk setiap permintaan

334

Saya perlu menetapkan beberapa tajuk Otorisasi setelah pengguna masuk, untuk setiap permintaan berikutnya.


Untuk mengatur tajuk untuk permintaan tertentu,

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

Referensi

Tetapi tidak mungkin untuk mengatur header permintaan secara manual untuk setiap permintaan dengan cara ini.

Bagaimana cara mengatur set header setelah pengguna masuk, dan juga menghapus header itu saat keluar?

Avijit Gupta
sumber

Jawaban:

379

Untuk menjawab, Anda mempertanyakan apakah Anda dapat menyediakan layanan yang membungkus Httpobjek asli dari Angular. Sesuatu seperti dijelaskan di bawah ini.

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

Dan alih-alih menyuntikkan Httpobjek Anda bisa menyuntikkan yang ini ( 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 );
    });
  }
}

Saya juga berpikir bahwa sesuatu dapat dilakukan dengan menggunakan penyedia multi untuk Httpkelas dengan menyediakan kelas Anda sendiri memperluas Httpsatu ... Lihat tautan ini: http://blog.thoughtram.io/angular2/2015/11/23/multi-providers -in-angular-2.html .

Thierry Templier
sumber
1
dimana 'this.http = http;' berasal dari, saya yakin kita perlu mendeklarasikannya sebelum menggunakan?
co2f2e
1
Header angular (fungsi set & append) "menormalkan" kunci header dan menjadikannya huruf kecil. Dari Headers.d.ts: // "Kumpulan karakter HTTP diidentifikasi oleh token case-insensitive" // Spec di tools.ietf.org/html/rfc2616 Bagi mereka yang tidak memiliki backend yang berfungsi oleh spec; inilah bypass: biarkan headersMap = .get (opsi, 'headers._headersMap', Peta baru ()); headersMap.set ('Otorisasi', [ .replace ( Bearer ${token}, / \ "/ g, '')]);
sangress
@DiegoUnanue Saya menggunakan versi final dari Angular 2 dan karya implementasi Thierry. Cukup ganti 'angular2' ke '@angular' di laporan impor.
f123
Mark Pieszak- haruskah saya menyertakan penyedia untuk HttpClient?
user3127109
sekarang TS melempar kesalahan: `Argumen tipe '{header: Header; } 'tidak dapat dialihkan ke parameter tipe' RequestOptionsArgs'`
elporfirio
142

Pencegat HTTP sekarang tersedia melalui yang baru HttpClientdari @angular/common/http, pada versi 4.3.x Angular dan seterusnya .

Cukup mudah untuk menambahkan header untuk setiap permintaan sekarang:

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

Ada prinsip kekekalan , itulah alasan permintaan harus dikloning sebelum menetapkan sesuatu yang baru di atasnya.

Karena mengedit tajuk adalah tugas yang sangat umum, sebenarnya ada jalan pintas untuk itu (sambil mengkloning permintaan):

const clonedRequest = req.clone({ setHeaders: { Authorization: 'Bearer 123' } });

Setelah membuat interseptor, Anda harus mendaftarkannya menggunakan penawaran HTTP_INTERCEPTORS.

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

@NgModule({
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: AddHeaderInterceptor,
    multi: true,
  }],
})
export class AppModule {}
Edmundo Rodrigues
sumber
Saya menerapkan ini dan ketika melakukan servis, saya bisa melihat header permintaan, namun ketika melakukan ng b prod dan menggunakan di dalam kucing jantan, saya tidak melihat header ... menggunakan spring-boot, kemana header pergi?
naoru
1
Tidak tahu apakah itu karena saya bekerja dengan API Express node, tetapi tidak berfungsi untuk saya bahkan dengan dokumen Angular resmi. : /
Maxime Lafarie
ERROR TypeError: CreateListFromArrayLike meminta non-objek
DAG
1
Bagaimana Anda menyuntikkan sesuatu ke dalam HttpInterceptor?
zaitsman
Saya telah menerapkan hal yang sama ini tetapi dalam header permintaan PUT dan DELETE API tidak berfungsi untuk saya.
Pooja
78

Memperluas BaseRequestOptionsmungkin sangat membantu dalam skenario ini. Lihat kode berikut:

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

Ini harus mencakup 'My-Custom-Header' di setiap panggilan.

Memperbarui:

Untuk dapat mengubah tajuk kapan saja Anda inginkan alih-alih kode di atas, Anda juga dapat menggunakan kode berikut untuk menambahkan tajuk baru:

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

untuk menghapus bisa Anda lakukan

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

Juga ada fungsi lain yang dapat Anda gunakan untuk mengatur nilai:

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

Solusi di atas masih belum sepenuhnya valid dalam konteks naskah. _defaultHeaders dilindungi dan tidak seharusnya digunakan seperti ini. Saya akan merekomendasikan solusi di atas untuk perbaikan cepat tetapi untuk jangka panjang lebih baik untuk menulis bungkus Anda sendiri di sekitar panggilan http yang juga menangani auth. Ambil contoh berikut dari auth0 yang lebih baik dan bersih.

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

Pembaruan - Juni 2018 Saya melihat banyak orang mencari solusi ini, tetapi saya menyarankan sebaliknya. Menambah tajuk secara global akan mengirimkan token autentikasi ke setiap panggilan api yang keluar dari aplikasi Anda. Jadi panggilan api pergi ke plugin pihak ketiga seperti interkom atau zendesk atau api lain juga akan membawa header otorisasi Anda. Ini mungkin menghasilkan kelemahan keamanan yang besar. Jadi alih-alih, gunakan interceptor secara global tetapi periksa secara manual apakah panggilan keluar menuju titik akhir api server Anda atau tidak dan kemudian pasang tajuk auth.

anit
sumber
1
this.http._defaultOptions.headers.delete ('My-Custom-Header') Jadi proses di atas dapat dipersingkat dengan mengikuti kode this.http._defaultOptions.headers.append ('My-New-Custom-Header', 'nilai baru ')
anit
2
@Distro ya, sekarang saya tidak akan merekomendasikan diri saya melakukan ini. Saya harus menemukan solusi ini karena keterbatasan beta sudut dan kebiasaan saya mengendalikan aliran auth secara global. Tapi saya percaya untuk saat ini github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts memiliki solusi yang lebih baik dan bersih.
anit
1
Masalah menggunakan BaseRequestOptions adalah konstruktornya dijalankan hanya sekali dalam masa aplikasi di browser. Jadi jika Anda ingin mengubah nilai header selama ini (mis. Csrf_token) Anda tidak dapat melakukannya dengan cara ini (bahkan mengesampingkan metode penggabungan di kelas ini tidak membantu :()
Kamil Kiełczewski
1
Masalahnya adalah bahwa jika Anda menggunakan perpustakaan pihak ke-3 wrapper yang mengakses HTTP secara langsung perlu ditulis ulang untuk menggunakannya. Saya masih tidak tahu bagaimana menyiasatinya. Pencegat sangat dibutuhkan. Tidak yakin apakah ada yang tahu cara yang lebih baik.
Piotr Stulinski
6
Hai, di angular4 _defaultOptionsdilindungi sehingga tidak dapat dipanggil dari layanan
Andurit
24

Meskipun saya menjawabnya sangat terlambat tetapi mungkin membantu orang lain. Untuk menyuntikkan tajuk ke semua permintaan saat @NgModuledigunakan, seseorang dapat melakukan hal berikut:

(Saya menguji ini dalam 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');
    }
}

Sekarang @NgModulelakukan hal berikut:

@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]
})
Shashank Agrawal
sumber
4
Anda memerlukan @Injectable dan mendefinisikan header di kelas, saya menguji berhasil oleh @Injectable () kelas ekspor CustomRequestOptions meluas BaseRequestOptions {header: Header = Header baru ({'Otorisasi': 'xxx'}); }
EasonBlack
baik, saya melakukan ini di 2.0.0, tidak memeriksa 2.0.1
EasonBlack
Catatan penting di sini saya mengalami masalah di mana tidak mungkin untuk menyuntikkan sesuatu CustomRequestOptionsbahkan ketika menggunakan @ Suntik / @ Suntik. Solusi yang saya sadari adalah memperluas RequestOptions, bukan BaseRequestOptions. Memberi BaseRequestOptionstidak akan berhasil, tetapi memperluas RequestOptionsmalah membuat DI berfungsi lagi.
parlemen
5
Solusi ini sederhana, tetapi jika pengguna akan keluar dan masuk kembali dan perubahan tokennya - itu tidak akan berfungsi lagi, karena Authorizationheader diatur hanya sekali pada aplikasi init.
Alex Paramonov
Ya, perbaiki @AlexeyVParamonov. Ini berguna hanya jika token diset sekali. Kalau tidak, kami akan menulis pencegat untuk kasus seperti yang Anda katakan.
Shashank Agrawal
15

Dalam Angular 2.1.2saya mendekati ini dengan memperluas sudut 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)
  }
}

kemudian di Penyedia Aplikasi saya, saya dapat menggunakan Pabrik kustom untuk memberikan '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(){

  }
}

sekarang saya tidak perlu mendeklarasikan setiap metode Http dan dapat digunakan httpseperti biasa di seluruh aplikasi saya.

jonnie
sumber
Jawaban ini bekerja paling baik untuk saya karena saya dapat memfilter url ke server api saya dan hanya menambahkan Token Auth ke panggilan yang dibuat untuk itu. Saya mengubah permintaan menjadi: request (url: string | Permintaan, opsi ?: RequestOptionsArgs): Dapat diamati <Response> {var _url: string = url.toString (); if (_url.indexOf ('api.myserver.com')> -1) {options = this._setCustomHeaders (options); } kembalikan super.request (url, opsi)}
Chris Holcomb
Dalam kasus saya withCredentials and Headers diambil dari parameter url dalam metode permintaan. Saya mengubah kode seperti ini: request (url: string | Request, options ?: RequestOptionsArgs): Observable <Response> {options = this._setCustomHeaders (options); if (typeof (url) === "object") {(<Request> url) .withCredentials = options.withCredentials; (<Request> url) .headers = options.headers; } return super.request (url, options)}
Argnist
The request()metode, yang Anda overloading, memiliki dua tanda tangan panggilan dan optionsproperti digunakan hanya ketika urlditetapkan sebagai string. Dalam kasus di mana urlturunan dari Request, optionsproperti hanya diabaikan. Ini bisa menyebabkan kesalahan yang sulit ditangkap. Silakan lihat jawaban saya untuk lebih jelasnya.
Slava Fomin II
Perhatikan bahwa solusi ini memiliki beberapa masalah dengan platform server . Namun ada solusi untuk menghindarinya .
Alireza Mirian
Ini bekerja untuk saya sampai sudut 4.2. 4.3 Memiliki pencegat.
cabaji99
12

Buat kelas Http kustom dengan memperluas HttpPenyedia Angular 2 dan cukup menimpa constructordan requestmetode di kelas Http kustom Anda. Contoh di bawah ini menambahkan Authorizationheader di setiap permintaan 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);
    };
  }
}

Kemudian konfigurasikan main Anda app.module.tsuntuk menyediakan XHRBackendsebagai ConnectionBackendpenyedia dan RequestOptionsuntuk kelas Http kustom Anda:

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

Setelah itu, Anda sekarang dapat menggunakan penyedia http khusus Anda di layanan Anda. Sebagai contoh:

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

Inilah panduan komprehensif - http://adonespitogo.com/articles/angular-2-extending-http-provider/

Adones Pitogo
sumber
Pendekatan ini sangat cocok untuk menggunakan penyedia kelas alternatif. Alih-alih "memberikan: HttpService" seperti yang Anda miliki dalam modul Anda, Anda bisa menggunakan "menyediakan: Http" memungkinkan Anda untuk bekerja dengan Http seperti yang biasanya Anda lakukan.
The Gilbert Arenas Dagger
Bagaimana saya bisa menambahkan properti tambahan ke kelas http yang diperluas ini? Misalnya, router: Router atau layanan injeksi kustom apa pun.
shafeequemat
@shafeequemat Anda tidak dapat melakukannya menggunakan ini. Anda dapat mendefinisikan metode lain di kelas http khusus Anda, misalnya setRouter(router). Atau Anda dapat membuat kelas lain dan menyuntikkan kelas http kustom Anda di sana, bukan sebaliknya.
Adones Pitogo
9

Untuk Angular 5 ke atas, kita dapat menggunakan HttpInterceptor untuk menggeneralisasi operasi permintaan dan respons. Ini membantu kami menghindari duplikasi:

1) Header umum

2) Menentukan jenis respons

3) Permintaan kueri

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

Kita dapat menggunakan kelas AuthHttpInterceptor ini sebagai penyedia untuk 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 {
}
Prachi
sumber
8

Lebih baik terlambat daripada tidak pernah ... =)

Anda dapat mengambil konsep extended BaseRequestOptions(dari sini https://angular.io/docs/ts/latest/guide/server-communication.html#!#override-default-request-options ) dan menyegarkan header "dengan cepat "(tidak hanya dalam konstruktor). Anda dapat menggunakan override properti pengambil / setter "header" seperti ini:

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 };
Александр Ильинский
sumber
sedikit pembaruan: untuk kinerja yang lebih baik Anda dapat mempertimbangkan untuk memindahkan semua header statis (seperti 'Tipe-Konten') ke konstruktor
Александр Ильинский
7

Inilah yang saya lakukan untuk menyetel token dengan setiap permintaan.

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

Dan mendaftar di app.module.ts

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule
    ],
    providers: [
        { provide: RequestOptions, useClass: CustomRequestOptions }
    ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Rajkeshwar Prasad
sumber
6

Berikut ini adalah versi perbaikan dari jawaban yang diterima, diperbarui untuk final 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<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());
    }
}

Tentu saja harus diperluas untuk metode seperti deletedan putjika diperlukan (saya belum membutuhkannya pada saat ini dalam proyek saya).

Keuntungannya adalah ada lebih sedikit kode yang digandakan dalam metode get/ post/ ....

Perhatikan bahwa dalam kasus saya, saya menggunakan cookie untuk otentikasi. Saya membutuhkan tajuk untuk i18n ( Accept-Languagetajuk) karena banyak nilai yang dikembalikan oleh API kami diterjemahkan dalam bahasa pengguna. Di aplikasi saya, layanan i18n menampung bahasa yang saat ini dipilih oleh pengguna.

Pierre Henry
sumber
bagaimana Anda membuat tslint untuk mengabaikan header seperti membiarkan?
Winnemucca
5

Bagaimana dengan Menjaga Layanan Terpisah seperti berikut

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

dan ketika Anda memanggil ini dari tempat lain gunakan this.httpClientService.addHeader("Authorization", "Bearer " + this.tok);

dan Anda akan melihat tajuk yang ditambahkan misalnya: - Otorisasi sebagai berikut

masukkan deskripsi gambar di sini

co2f2e
sumber
5

Setelah beberapa penyelidikan, saya menemukan cara terakhir dan paling mudah adalah dengan memperpanjang BaseRequestOptionsyang saya inginkan.
Berikut ini adalah cara saya mencoba dan menyerah karena beberapa alasan:
1. memperluas BaseRequestOptions, dan menambahkan header dinamis di constructor(). Itu tidak bisa berfungsi jika saya login. Itu akan dibuat sekali. Jadi tidak dinamis.
2. memperpanjang Http. Alasan yang sama seperti di atas, saya tidak dapat menambahkan header dinamis di constructor(). Dan jika saya menulis ulang request(..)metode, dan mengatur tajuk, seperti ini:

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

Anda hanya perlu menimpa metode ini, tetapi tidak setiap metode get / post / put.

3. Dan solusi pilihan saya adalah rentangkan BaseRequestOptionsdan timpa 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()fungsi ini akan dipanggil untuk setiap permintaan.

Mavlarn
sumber
Di antara semua jawaban yang diberikan, ini adalah jawaban yang menarik perhatian saya karena saya sudah mencari solusi yang didasarkan pada perluasan BaseRequestOptions. Namun, sayangnya, ini tidak berhasil untuk saya. ada kemungkinan alasan?
peringatan
membuatnya bekerja. solusi ini baik dan saya punya masalah di server saya. Saya harus melakukan beberapa konfigurasi untuk permintaan pra-penerbangan CORS. lihat tautan ini stackoverflow.com/a/43962690/3892439
vigamage
Bagaimana Anda mengikat AuthRequestOptionsaplikasi lainnya? Saya mencoba meletakkan ini di providersbagian tetapi tidak melakukan apa-apa.
Travis Parks
Anda harus mengganti penyedia untuk RequestOptions, bukan BaseRequestOptions. angular.io/api/http/BaseRequestOptions
Travis Parks
Di aplikasi saya, saya hanya memperpanjang BaseRequestOptions, dan itu sudah memperpanjang RequestOptions. Kemudian di app.module, Anda harus mengatur penyedia:{ provide: RequestOptions, useClass: AuthRequestOptions }
Mavlarn
5

Meskipun saya menjawab ini sangat terlambat tetapi jika ada yang mencari solusi yang lebih mudah.

Kita bisa menggunakan angular2-jwt. angular2-jwt berguna secara otomatis melampirkan JSON Web Token (JWT) sebagai header Otorisasi ketika membuat permintaan HTTP dari aplikasi Angular 2.

Kita dapat mengatur tajuk global dengan opsi konfigurasi lanjutan

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

Dan mengirim token per permintaan seperti

    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')
    );
}
KNimhan
sumber
akan sangat membantu untuk membuka github.com/auth0/angular2-jwt#installation dan mengadaptasi jawaban ini menggunakan panduan instalasi mereka
Zuriel
4

Saya suka ide untuk menimpa opsi default, ini sepertinya solusi yang bagus.

Namun, jika Anda ingin memperluas Httpkelas. Pastikan untuk membaca ini sampai selesai!

Beberapa jawaban di sini sebenarnya menunjukkan kelebihan request()metode yang tidak benar , yang dapat menyebabkan kesalahan yang sulit ditangkap dan perilaku aneh. Saya sendiri telah menemukan ini.

Solusi ini didasarkan pada request()implementasi metode di Angular 4.2.x, tetapi harus kompatibel di masa depan:

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;

  }

}

Perhatikan bahwa saya mengimpor kelas asli dengan cara ini import { Http as NgHttp } from '@angular/http';untuk mencegah bentrokan nama.

Masalah yang dibahas di sini adalah bahwa request()metode memiliki dua tanda tangan panggilan yang berbeda. Saat Requestobjek dilewatkan alih-alih URL string, optionsargumen diabaikan oleh Angular. Jadi kedua kasus harus ditangani dengan benar.

Dan inilah contoh cara mendaftarkan kelas yang diganti ini dengan wadah 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
  );
}

Dengan pendekatan seperti itu Anda bisa menyuntikkan Httpkelas secara normal, tetapi kelas yang diganti Anda akan disuntikkan secara ajaib. Ini memungkinkan Anda untuk mengintegrasikan solusi Anda dengan mudah tanpa mengubah bagian lain dari aplikasi (polimorfisme sedang bekerja).

Cukup tambahkan httpProviderke providersproperti metadata modul Anda.

Slava Fomin II
sumber
1

Yang paling sederhana

Buat config.tsfile

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

Kemudian pada Anda service, cukup impor config.tsfile

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

Saya pikir itu yang paling sederhana dan paling aman.

Joshua Fabillar
sumber
0

Ada beberapa perubahan untuk sudut 2.0.1 dan lebih tinggi:

    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 { }
Carlos Casallas
sumber
Tidak berhasil, coba sendiri. Tidak dipanggil apa pun selain menyegarkan.
Phil
0

Saya telah dapat memilih solusi yang lebih sederhana> Tambahkan Header baru ke opsi default menggabungkan atau memuat dengan fungsi get (atau lainnya) api Anda.

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

Tentu saja Anda dapat mengeksternalkan Header ini dalam opsi default atau apa pun di kelas Anda. Ini ada di API ekspor kelas.onic @Injectable () yang dihasilkan Ionic {}

Ini sangat cepat dan bekerja untuk saya. Saya tidak ingin format json / ld.

Paul Leclerc
sumber
-4

Anda dapat menggunakan canActiverute Anda, seperti:

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

Diambil dari: https://auth0.com/blog/angular-2-authentication

DI
sumber