Açısal - Her istek için üstbilgileri ayarla


334

Sonraki her istek için, kullanıcı oturum açtıktan sonra bazı Yetkilendirme başlıklarını ayarlamam gerekiyor.


Belirli bir istek için üstbilgi ayarlamak üzere,

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

Referans

Ancak, her istek için istek üstbilgilerini bu şekilde manuel olarak ayarlamak mümkün olmaz.

Kullanıcı oturum açtıktan sonra ayarlanan üstbilgileri nasıl ayarlayabilir ve çıkışta bu başlıkları da kaldırabilirim?



Yanıtlar:


379

Yanıtlamak için, orijinal Httpnesneyi Açısal'dan saran bir hizmet sağlayabileceğinizi sorgulayabilirsiniz . Aşağıda anlatıldığı gibi bir şey.

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

Ve Httpnesneyi enjekte etmek yerine bunu enjekte edebilirsiniz ( 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 );
    });
  }
}

Ben de bir Httpsınıf genişleterek kendi sınıfını genişleterek sınıf için çoklu sağlayıcılar kullanılarak yapılabileceğini düşünüyorum Http... Bu bağlantıya bakın: http://blog.thoughtram.io/angular2/2015/11/23/multi-providers -in-açısal-2.html .


1
'this.http = http;' kullanmadan önce bildirmemiz gerektiğine inanıyorum?
co2f2e

1
açısal Başlıklar (set & append işlevleri) başlık anahtarını "normalleştirir" ve küçük harf yapar. Headers.d.ts adresinden: // "HTTP karakter kümeleri büyük / küçük harfe duyarlı olmayan belirteçlerle tanımlanır" // Spec on tools.ietf.org/html/rfc2616 Spec tarafından çalışan bir arka ucu olmayanlar için; İşte bir bypass: let headersMap = .get (seçenekler, 'headers._headersMap', yeni Harita ()); headersMap.set ('Yetkilendirme', [ .replace ( Bearer ${token}, / \ "/ g, '')]);
19'da sangress

@DiegoUnanue Angular 2 ve Thierry'nin uygulama çalışmalarının son sürümünü kullanıyorum. İçe aktarma ifadelerinde 'angular2' yerine '@angular' ifadesini değiştirmeniz yeterlidir.
f123

Mark Pieszak- HttpClient sağlayıcılarını dahil etmeli miyim?
user3127109

şimdi TS hata veriyor: `` Bağımsız değişken '' {headers: Headers; } ','
RequestOptionsArgs

142

HTTP önleyicilerin vardır artık yeni aracılığıyla HttpClientgelen @angular/common/http, Açısal 4.3.x sürümleri ve öbür itibariyle .

Şimdi her istek için bir başlık eklemek oldukça basit:

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

Değişmezlik ilkesi var , bu yüzden yeni bir şey ayarlamadan önce isteğin klonlanması gerekiyor.

Üstbilgileri düzenlemek çok yaygın bir görev olduğundan, aslında bunun için bir kısayol vardır (isteği klonlarken):

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

Durdurucu oluşturduktan sonra, HTTP_INTERCEPTORSsağlama aracını kullanarak kaydettirmelisiniz .

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

@NgModule({
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: AddHeaderInterceptor,
    multi: true,
  }],
})
export class AppModule {}

Bunu uyguladım ve ng hizmet yaparken istek başlıklarını görebilirim, ancak ng b prod yaparken ve bir tomcat içinde konuşlandırırken, başlıkları görmüyorum ... spring-boot kullanarak, başlıklar nereye gitti?
naoru

1
Express düğüm API'siyle çalıştığımdan emin değilim, ancak resmi Angular doc ile bile benim için çalışmıyor. : /
Maxime Lafarie

HATA TypeError: Nesne dışı olarak oluşturulmuş CreateListFromArrayLike
DAG

1
HttpInterceptor'a nasıl bir şey enjekte edersiniz?
zaitsman

Aynı şeyleri uyguladım ama PUT ve DELETE API istek başlığında benim için çalışmıyor.
Pooja

78

BaseRequestOptionsBu senaryoda genişletme çok yardımcı olabilir. Aşağıdaki kodu kontrol edin:

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

Bu, her çağrıda 'Özel Özel Başlığımı' içermelidir.

Güncelleme:

Yukarıdaki kod yerine istediğiniz zaman üstbilgiyi değiştirmek için yeni bir üstbilgi eklemek için aşağıdaki kodu da kullanabilirsiniz:

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

silmek için yapabilirsin

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

Ayrıca, değeri ayarlamak için kullanabileceğiniz başka bir işlev daha vardır:

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

Yukarıdaki çözüm hala daktilo bağlamında tamamen geçerli değildir. _defaultHeaders korumalı ve bu şekilde kullanılmaması gerekiyor. Hızlı bir düzeltme için yukarıdaki çözümü tavsiye ederim ama uzun vadede, aynı zamanda auth işleyen http aramaları etrafında kendi sarmalayıcı yazmak daha iyidir. Auth0'dan daha iyi ve temiz bir örnek alın.

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

Güncelleme - Haziran 2018 Bu çözüm için birçok insanın gittiğini görüyorum, ancak başka türlü tavsiye ederim. Genel olarak üstbilgi eklemek , uygulamanızdan çıkan her api çağrısına yetkilendirme jetonu gönderir . Böylece api intercom veya zendesk veya başka bir api gibi üçüncü taraf eklentilere giden çağrılar da yetkilendirme başlığınızı taşır. Bu büyük bir güvenlik açığına neden olabilir. Bunun yerine, önleme aracını global olarak kullanın, ancak giden çağrının sunucunuzun api uç noktasına doğru olup olmadığını manuel olarak kontrol edin ve ardından kimlik doğrulama başlığı ekleyin.


1
this.http._defaultOptions.headers.delete ('My-Custom-Header') Yukarıdaki işlem this.http._defaultOptions.headers.append ('My-New-Custom-Header', 'yeni değer koduyla kısaltılabilir ')
anit

2
@Dinistro evet, şimdi bunu kendime tavsiye etmeyeceğim. Açısal beta sınırlamaları ve global olarak auth akışını kontrol etme alışkanlığım nedeniyle bu geçici çözümü bulmak zorunda kaldım. Ama şimdilik github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts daha iyi ve temiz bir çözüm olduğuna inanıyorum .
anit

1
BaseRequestOptions kullanmanın problemi, yapıcısının tarayıcıda uygulama ömründe yalnızca bir kez çalıştırılmasıdır. Bu nedenle, zaman içinde başlık değerini değiştirmek istiyorsanız (örn. Csrf_token) bu şekilde yapamazsınız (bu sınıftaki birleştirme yöntemini geçersiz kılmak bile yardımcı olmaz :()
Kamil Kiełczewski

1
Sorun, bir sarıcı kullanıyorsanız, HTTP'ye erişen üçüncü taraf kitaplıkların doğrudan kullanılması için yeniden yazılması gerekir. Hala bunun üstesinden nasıl geleceğimi bilmiyorum. Bir durdurucu gerçekten gerekli. Kimse daha iyi bir yol biliyor mu emin değilim.
Piotr Stulinski

6
Merhaba, angular4 _defaultOptionskorumalı, bu yüzden hizmetten
çağrılamaz

24

Çok geç cevap vermeme rağmen başka birine yardımcı olabilir. @NgModuleKullanıldığında tüm isteklere üstbilgi enjekte etmek için aşağıdakiler yapılabilir:

(Bunu Açısal 2.0.1'de test ettim)

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

Şimdi @NgModuleaşağıdakileri yapın:

@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 gerekir ve sınıfta üstbilgileri tanımlamak, @Injectable () ihracat sınıfı tarafından başarılı bir şekilde test edilmiştir CustomRequestOptions BaseRequestOptions {headers: Headers = new Headers ({'Authorization': 'xxx'}); }
EasonBlack

iyi, ben 2.0.0 bunu yaptım, 2.0.1 kontrol etmedi
EasonBlack

Burada önemli not, CustomRequestOptions@ Inject / @ Injectable kullanırken bile bir şey enjekte etmenin imkansız olduğu bir sorunla karşılaştım . Fark ettiğim çözüm uzatmaktı RequestOptions, değil BaseRequestOptions. Sağlamak BaseRequestOptionsişe yaramaz, RequestOptionsbunun yerine genişletmek DI'nin tekrar çalışmasını sağlar.
parlamento

5
Bu çözüm basittir, ancak kullanıcı oturumu kapatıp tekrar oturum açarsa ve jetonu değiştirirse - artık çalışmaz, çünkü Authorizationbaşlık uygulama başlangıcında yalnızca bir kez ayarlanır.
Alex Paramonov

Evet, @AlexeyVParamonov'u düzeltin. Bu, yalnızca belirteç bir kez ayarlanmışsa kullanışlıdır. Aksi takdirde, dediğin gibi dava için durdurucuları yazacağız.
Shashank Agrawal

15

Gelen Angular 2.1.2bir genişleterek yaklaşmaktadır açısal 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)
  }
}

daha sonra Uygulama Sağlayıcılarımda 'Http' sağlamak için özel bir Fabrika kullanabildim

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(){

  }
}

Şimdi her Http yöntemini bildirmem gerekmiyor ve httpbaşvurum boyunca normal olarak kullanabiliyor .


Bu yanıt benim için en iyi sonucu verdi. İsteği şu şekilde değiştirdim: request (url: string | Request, options ?: RequestOptionsArgs): Observable <Response> {var _url: string = url.toString (); if (_url.indexOf ('api.myserver.com')> -1) {options = this._setCustomHeaders (seçenekler); } return super.request (url, seçenekler)}
Chris Holcomb

Benim durumumda Kimlik Bilgileri ve Başlıklar istek yönteminde url parametresinden alınmıştır. Kodu şu şekilde değiştirdim: request (url: string | Request, options ?: RequestOptionsArgs): Gözlenebilir <Response> {options = this._setCustomHeaders (options); if (typeof (url) === "nesne") {(<Request> url) .withCredentials = options.withCredentials; (<Request> url) .headers = options.headers; } dönüş super.request (url, seçenekler)}
Argnist

request()Eğer aşırı yükleniyor yöntem, iki çağrı imzalarını vardır ve optionsne zaman özellik yalnızca kullanılan urldize olarak belirtilmiş. Durumda urlbir örneğini olduğunu Request, optionsmülkiyet sadece göz ardı edilir. Bu, hataları yakalamak zor olabilir. Daha fazla bilgi için lütfen cevabıma bakın.
Slava Fomin II

Bu çözümün sunucu platformuyla ilgili bazı sorunları olduğunu unutmayın . Ancak bundan kaçınmak için geçici çözümler vardır .
Alireza Mirian

Bu açısal 4.2'ye kadar benim için çalıştı. 4.3 Durduruculara sahiptir.
cabaji99

12

Angular 2 HttpSağlayıcısı'nı genişleterek özel bir Http sınıfı oluşturun ve özel Http sınıfınızdaki constructorve requestyöntemini geçersiz kılın . Aşağıdaki örnek Authorizationher http isteğine üstbilgi ekler .

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

Ardından ana sunucunuzu , sağlayıcı olarak ve özel Http sınıfınıza app.module.tssağlayacak şekilde yapılandırın :XHRBackendConnectionBackendRequestOptions

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

Bundan sonra, artık hizmetlerinizde özel http sağlayıcınızı kullanabilirsiniz. Örneğin:

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

İşte kapsamlı bir rehber - http://adonespitogo.com/articles/angular-2-extending-http-provider/


Bu yaklaşım alternatif bir sınıf sağlayıcısı kullanmak için çok uygundur. Modülünüzde olduğu gibi "Provide: HttpService" yerine, normalde yaptığınız gibi Http ile çalışmanıza izin veren "Provide: Http" kullanabilirsiniz.
Gilbert Arenas Hançer

Bu genişletilmiş http sınıfına nasıl ek özellikler ekleyebilirim? Örneğin, yönlendirici: Yönlendirici veya herhangi bir özel enjekte edilebilir hizmet.
shafeequemat

@shafeequemat Bunu kullanarak bunu yapamazsınız. Örneğin, özel http sınıfınızda başka bir yöntem tanımlayabilirsiniz setRouter(router). Veya başka bir sınıf oluşturabilir ve bunun yerine özel http sınıfınızı enjekte edebilirsiniz.
Adones Pitogo

9

Açısal 5 ve üstü için, istek ve yanıt işlemlerini genelleştirmek için HttpInterceptor'u kullanabiliriz. Bu, çoğaltmaktan kaçınmamıza yardımcı olur:

1) Ortak başlıklar

2) Yanıt türünü belirtme

3) Sorgulama talebi

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

Bu AuthHttpInterceptor sınıfını HttpInterceptors için sağlayıcı olarak kullanabiliriz:

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

Hiç olmadığı kadar iyi geç ... =)

Genişletilmiş BaseRequestOptions(buradan https://angular.io/docs/ts/latest/guide/server-communication.html#!#override-default-request-options ) kavramını alabilir ve üstbilgileri anında yenileyebilirsiniz " "(yalnızca yapıcıda değil). Getter / setter "headers" özelliği geçersiz kılma yöntemini şu şekilde kullanabilirsiniz:

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

küçük güncelleme: daha iyi performans için tüm statik başlıkları ('Content-Type' gibi)
kurucuya taşımayı düşünebilirsiniz

7

Her istekte jeton ayarlamak için böyle yaptım.

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

Ve app.module.ts dosyasına kaydolun

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

6

Angular2 finali için güncellenmiş kabul edilen cevabın geliştirilmiş bir versiyonu:

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

Tabii ki , ihtiyaç duyulan deleteve putgerekirse yöntemler için genişletilmelidir (projemde henüz bu noktada onlara ihtiyacım yok).

Avantajı, get/ post/ ... yöntemlerinde daha az çoğaltılmış kod olmasıdır .

Benim durumumda kimlik doğrulama için çerezler kullandığımı unutmayın. API'mız Accept-Languagetarafından döndürülen birçok değer kullanıcının dilinde çevrildiğinden i18n ( başlık) için başlığa ihtiyacım vardı . Uygulamamda i18n hizmeti, kullanıcı tarafından seçili olan dili barındırıyor.


tslint'i üstbilgileri izinsiz olarak yoksaydın
Winnemucca

5

Ayrı bir Hizmeti aşağıdaki gibi tutmaya ne dersiniz?

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

ve bunu başka bir yerden aradığınızda this.httpClientService.addHeader("Authorization", "Bearer " + this.tok);

ve eklenmiş başlığı göreceksiniz örn .: - Yetkilendirme aşağıdaki gibi

resim açıklamasını buraya girin


5

Biraz araştırmadan sonra, nihai ve en kolay yolu BaseRequestOptionstercih ettiğimi uzatmak buldum.
Denemek ve bazı nedenlerden vazgeçmek için kullandığım yöntemler şunlardır:
1. BaseRequestOptionsDinamik başlıkları genişletin ve ekleyin constructor(). Giriş yaparsam çalışmaz. Bir kez oluşturulacak. Yani dinamik değil.
2. uzatın Http. Yukarıdaki ile aynı sebepten dolayı dinamik başlıklar ekleyemiyorum constructor(). Ve eğer request(..)yöntemi yeniden yazıp başlıkları şöyle ayarlarsam:

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

Sadece bu yöntemin üzerine yazmanız gerekir, ancak her get / post / put yönteminin değil.

3.Ve benim tercih ettiğim çözüm uzat BaseRequestOptionsve üzerine yaz 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;
 }
}

bu merge()işlev her istek için çağrılır.


Verilen tüm cevaplar arasında, genişlemeye dayalı bir çözüm için gitmiş olduğumdan beri dikkatimi çeken cevap budur BaseRequestOptions. Ancak, ne yazık ki, bu benim için işe yaramadı. herhangi bir olası neden var mı?
vigamage

işe yaradı. Bu çözüm gayet iyi ve sunucumda bir sorun vardı. Uçuş öncesi CORS istekleri için bazı yapılandırmalar yapmak zorunda kaldım. bu bağlantıya bakın stackoverflow.com/a/43962690/3892439
vigamage

AuthRequestOptionsUygulamanın geri kalanına nasıl bağlanırsınız? Bunu providersbölüme koymaya çalıştım ama hiçbir şey yapmadı.
Travis Parks

İçin sağlayıcıyı geçersiz kılmalısınız RequestOptions, değil BaseRequestOptions. angular.io/api/http/BaseRequestOptions
Travis Parks

Benim app, sadece BaseRequestOptions genişletmek ve zaten RequestOptions genişletir. Sonra app.module, sağlayıcıları ayarlamanız gerekir:{ provide: RequestOptions, useClass: AuthRequestOptions }
Mavlarn

5

Buna çok geç cevap vermeme rağmen, eğer biri daha kolay bir çözüm arıyorsa.

Açısal2-jwt kullanabiliriz. angular2-jwt, Angular 2 uygulamasından HTTP istekleri yaparken bir JSON Web Simgesini (JWT) Yetkilendirme başlığı olarak otomatik olarak eklemek için kullanışlıdır.

Gelişmiş yapılandırma seçeneği ile global başlıklar ayarlayabiliriz

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

Ve istek jetonu göndermek gibi

    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 adresine gidip kurulum kılavuzunu kullanarak bu cevabı uyarlamanız yararlı olacaktır
Zuriel

4

Varsayılan seçenekleri geçersiz kılma fikrini seviyorum, bu iyi bir çözüm gibi görünüyor.

Ancak, Httpsınıfı genişletmeye hazırsanız. Bunu mutlaka okuyun!

Burada bazı yanıtlar aslında request()yakalanması zor hatalara ve garip davranışlara neden olabilecek yöntemin yanlış aşırı yüklenmesini gösteriyor . Bunu kendim tökezledim.

Bu çözüm, request()Angular'da yöntem uygulanmasına dayanmaktadır 4.2.x, ancak geleceğe uyumlu olmalıdır:

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';İsim çakışmalarını önlemek için orijinal sınıfı bu şekilde içe aktardığımı unutmayın .

Burada ele alınan sorun, request()yöntemin iki farklı çağrı imzası olmasıdır. Ne zaman Requestnesne URL yerine geçer string, optionsargüman açısal tarafından göz ardı edilir. Bu nedenle her iki durumda da uygun şekilde ele alınmalıdır.

Ve bu geçersiz kılınan sınıfı DI konteynerine nasıl kaydedeceğinize dair bir örnek:

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

Böyle bir yaklaşımla Httpsınıfı normal olarak enjekte edebilirsiniz , ancak geçersiz kılınan sınıfınız sihirli bir şekilde enjekte edilecektir. Bu, uygulamanın diğer kısımlarını değiştirmeden (eylemdeki polimorfizm) çözümünüzü kolayca entegre etmenizi sağlar.

Sadece eklemek httpProvideriçin providerssizin modül meta özelliği.


1

En basiti

config.tsDosya oluştur

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

Ardından service, config.tsdosyayı içe aktarın

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

En basit ve en güvenli olduğunu düşünüyorum.


0

Açısal 2.0.1 ve üstü için bazı değişiklikler vardı:

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

Çalışmıyor, kendim denedim. Yenilemekten başka bir şey çağrılmaz.
Phil

0

Daha basit bir çözüm seçebilirim> api get (veya diğer) işlevinizle birleştirme veya yükleme varsayılan seçeneklerine yeni bir Başlık ekleyin.

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

Tabii ki bu Üstbilgileri varsayılan seçeneklerde veya sınıfınızdaki her şeyde dışa aktarabilirsiniz. Bu, İyonik olarak üretilen api.ts @Injectable () ihracat sınıfı API'sında {}

Çok hızlı ve benim için çalışıyor. Json / ld formatını istemedim.


-4

canActiveGüzergahlarınızda şu şekilde kullanabilirsiniz :

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

Alındığı yer: https://auth0.com/blog/angular-2-authentication

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.