Angular 2 делает за вас много отличной работы. Но он не делает всего, что вы могли бы ожидать. Чего он не делает, так это не устанавливает много заголовков HTTP-запросов.

Теперь это имеет смысл, поскольку Angular не знает, что вы делаете с запросом, поэтому вам действительно нужно это сделать. Но большинство запросов Http, сделанных с помощью службы Http, будут для сериализованных данных JSON. Однако запрос по умолчанию не добавляет заголовков, чтобы сервер знал об этом. В результате разные браузеры будут выполнять очень разные запросы.

Это пример запроса Http, сделанного Chrome:

GET http://localhost:4200/movies.json HTTP/1.1Host: localhost:4200Connection: keep-aliveUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36Accept: */*
Referer: http://localhost:4200/
Accept-Encoding: gzip, deflate, sdch, brAccept-Language: en-US,en;q=0.8,nl;q=0.6
If-None-Match: W/"3a4c7-1590757b458"
If-Modified-Since: Fri, 16 Dec 2016 11:15:05 GMT

И это тот же запрос, сделанный с FireFox:

GET http://localhost:4200/movies.json HTTP/1.1Host: localhost:4200User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflate
Referer: http://localhost:4200/
Connection: keep-aliveIf-Modified-Since: Fri, 16 Dec 2016 11:15:05 GMT
If-None-Match: W/"3a4c7-1590757b458"
Cache-Control: max-age=0

Заметили разницу между двумя запросами? И особенно заголовок Accept, где Chrome утверждает, что принимает что-либо, а FireFox указывает предпочтение HTML или XML.

Добавление заголовков HTTP

Установить заголовки HTTP для запроса несложно. При вызове функции Http.get() вы можете указать заголовки, и все в порядке.

@Injectable()
export class MoviesService {
  constructor(private http: Http) { }
  getMovies(): Observable<Movie[]> {
    var options = new RequestOptions({
    headers: new Headers({
      'Accept': 'application/json' }) });
    return this.http
      .get('/movies.json', options)
      .map(resp => resp.json()); 
  }
}

Однако делать это в каждой службе, которая выполняет HTTP-запрос, довольно утомительно и легко забыть, поэтому должен быть более простой способ.

BaseRequestOptions и внедрение зависимостей спешат на помощь

Как это бывает, Angular использует тип BaseRequestOptions по умолчанию для всех параметров. Так что, если мы можем просто изменить это значение по умолчанию, мы готовы к работе. И это именно то, что позволит нам сделать внедрение зависимостей.

Сначала нам нужно определить наш собственный класс параметров запроса по умолчанию с любыми настройками, которые вы хотели бы. В этом случае я просто добавляю два заголовка.

@Injectable()
export class DefaultRequestOptions extends BaseRequestOptions {
  headers = new Headers({
    'Accept': 'application/json',
    'X-Requested-By':'Angular 2', 
  });
}

Затем мы настраиваем провайдера DI для использования класса out вместо класса по умолчанию.

@NgModule({
  // Other settings 
  providers: [ 
    MoviesService, 
    {
      provide: RequestOptions, 
      useClass: DefaultRequestOptions 
    }
  ],
})
export class AppModule { }

И мы готовы работать с каждым Http-запросом, используя наши два заголовка по умолчанию. Вот пример из Chrome.

GET http://localhost:4200/movies.json HTTP/1.1Host: localhost:4200Connection: keep-aliveCache-Control: max-age=0Accept: application/jsonX-Requested-By: Angular 2User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
Referer: http://localhost:4200/
Accept-Encoding: gzip, deflate, sdch, brAccept-Language: en-US,en;q=0.8,nl;q=0.6
If-None-Match: W/"3a4c7-1590757b458"
If-Modified-Since: Fri, 16 Dec 2016 11:15:05 GMT

Добавление динамических заголовков Http

Эти заголовки великолепны, но есть одно ограничение. Эти заголовки всегда одинаковы. А с некоторыми заголовками, например аутентификацией, вы можете захотеть контролировать фактические значения во время запроса. Оказывается, он тоже не очень сложный. Каждый запрос объединяет параметры и, следовательно, заголовки из текущего запроса с параметрами запроса по умолчанию, используя функцию слияния. Поскольку мы можем переопределить это, мы можем добавить любой динамический заголовок, который захотим.

@Injectable()
export class DefaultRequestOptions extends BaseRequestOptions {
  headers = new Headers({
    'Accept': 'application/json',
    'X-Requested-By':'Angular 2', 
  }); 
  merge(options?: RequestOptionsArgs): RequestOptions {
    var newOptions = super.merge(options);
    newOptions.headers.set('X-Requested-At', 
      new Date().toISOString());
    return newOptions; 
  }
}

Сладкий :-)

Первоначально опубликовано на сайте blogs.msmvps.com 16 декабря 2016 г.