Eu gosto da ideia de substituir as opções padrão, essa parece ser uma boa solução.
No entanto, se você estiver disposto a estender o Http
classe. Não deixe de ler isso!
Algumas respostas aqui estão realmente mostrando sobrecarga incorreta de request()
método, o que pode levar a erros difíceis de capturar e comportamento estranho. Eu já me deparei com isso.
Esta solução é baseada na request()
implementação do método em Angular 4.2.x
, mas deve ser compatível com o futuro:
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;
}
}
Observe que estou importando a classe original dessa maneira import { Http as NgHttp } from '@angular/http';
para evitar conflitos de nome.
O problema abordado aqui é que o request()
método possui duas assinaturas de chamada diferentes. Quando o Request
objeto é passado em vez da URL string
, o options
argumento é ignorado pelo Angular. Portanto, os dois casos devem ser tratados adequadamente.
E aqui está o exemplo de como registrar essa classe substituída no contêiner 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
);
}
Com essa abordagem, você pode injetar Http
classe normalmente, mas sua classe substituída será injetada magicamente. Isso permite que você integre sua solução facilmente, sem alterar outras partes do aplicativo (polimorfismo em ação).
Basta adicionar httpProvider
à providers
propriedade dos metadados do seu módulo.