Podoba mi się pomysł zastąpienia domyślnych opcji, wydaje się to dobrym rozwiązaniem.
Jeśli jednak zamierzasz rozszerzyć Httpklasę. Przeczytaj to!
Niektóre odpowiedzi tutaj pokazują nieprawidłowe przeładowanie request()metody, co może prowadzić do trudnych do uchwycenia błędów i dziwnego zachowania. Natknąłem się na to sam.
To rozwiązanie jest oparte na request()implementacji metod w Angular 4.2.x, ale powinno być kompatybilne w przyszłości:
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;
}
}
Zauważ, że importuję oryginalną klasę w ten sposób import { Http as NgHttp } from '@angular/http';, aby zapobiec konfliktom nazw.
Problem rozwiązany tutaj polega na tym, że request()metoda ma dwie różne sygnatury wywołań. Gdy Requestobiekt jest przekazywany zamiast adresu URL string, optionsargument jest ignorowany przez Angular. Tak więc oba przypadki muszą być odpowiednio obsługiwane.
A oto przykład, jak zarejestrować tę przesłoniętą klasę w kontenerze 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
);
}
Przy takim podejściu możesz wstrzykiwać Http normalnie klasę, ale zamiast tego twoja przesłonięta klasa zostanie wstrzyknięta magicznie. Pozwala to na łatwą integrację rozwiązania bez zmiany innych części aplikacji (polimorfizm w akcji).
Wystarczy dodać httpProviderdo providerswłaściwości metadanych modułu.