Podoba mi się pomysł zastąpienia domyślnych opcji, wydaje się to dobrym rozwiązaniem.
Jeśli jednak zamierzasz rozszerzyć Http
klasę. 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 Request
obiekt jest przekazywany zamiast adresu URL string
, options
argument 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ć httpProvider
do providers
właściwości metadanych modułu.