Мне нравится идея переопределить параметры по умолчанию, это кажется хорошим решением.
Тем не менее, если вы собираетесь расширить Http
класс. Обязательно прочитайте это до конца!
Некоторые ответы здесь на самом деле показывают неправильную перегрузку request()
метода, что может привести к трудно обнаруживаемым ошибкам и странному поведению. Я наткнулся на это сам.
Это решение основано на request()
реализации метода в Angular 4.2.x
, но должно быть совместимым с будущим:
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';
, чтобы предотвратить конфликт имен.
Проблема, решаемая здесь, состоит в том, что request()
метод имеет две разные сигнатуры вызовов. Когда Request
объект передается вместо URL string
, этот options
аргумент игнорируется Angular. Таким образом, оба случая должны быть правильно обработаны.
И вот пример того, как зарегистрировать этот переопределенный класс в контейнере 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
);
}
При таком подходе вы можете вводить Http
класс обычным способом, но вместо этого ваш переопределенный класс будет вводиться магическим образом. Это позволяет вам легко интегрировать ваше решение, не изменяя другие части приложения (полиморфизм в действии).
Просто добавьте httpProvider
в providers
свойство метаданных вашего модуля.