Adding a HTTP header to the Angular HttpClient doesn't send the header, why?
Asked Answered
S

10

249

Here is my code:

import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http';

logIn(username: string, password: string) {
    const url = 'http://server.com/index.php';
    const body = JSON.stringify({username: username,
                                 password: password});
    const headers = new HttpHeaders();
    headers.set('Content-Type', 'application/json; charset=utf-8');
    this.http.post(url, body, {headers: headers}).subscribe(
        (data) => {
            console.log(data);
        },
        (err: HttpErrorResponse) => {
            if (err.error instanceof Error) {
                console.log('Client-side error occured.');
            } else {
                console.log('Server-side error occured.');
            }
        }
    );
}

and here the network debug:

Request Method:POST
Status Code:200 OK
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Cache-Control:no-cache
Connection:keep-alive
Content-Length:46
Content-Type:text/plain

and Data are stored in 'Request Payload' but in my server doesn't received the POST values:

print_r($_POST);
Array
(
)

I believe the error comes from the header not set during the POST, what did I do wrong?

Shawannashawl answered 24/7, 2017 at 17:38 Comment(1)
Yes, thanks! But after not receiving data on my Back-end, I went to application/x-www-form-urlencoded. Anyway the main question is anserwerdShawannashawl
S
423

The instances of the new HttpHeader class are immutable objects. Invoking class methods will return a new instance as result. So basically, you need to do the following:

let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8');

or

const headers = new HttpHeaders({'Content-Type':'application/json; charset=utf-8'});

Update: adding multiple headers

let headers = new HttpHeaders();
headers = headers.set('h1', 'v1').set('h2','v2');

or

const headers = new HttpHeaders({'h1':'v1','h2':'v2'});

Update: accept object map for HttpClient headers & params

Since 5.0.0-beta.6 is now possible to skip the creation of a HttpHeaders object an directly pass an object map as argument. So now its possible to do the following:

http.get('someurl',{
   headers: {'header1':'value1','header2':'value2'}
});
Sisneros answered 24/7, 2017 at 17:50 Comment(16)
Interesting. So, for us coming from OO world, set method name is somewhat misleading.Mckeown
What if I want to set multiple headers? I've tried to chain the comment HttpHeaders().set(..).set(..) but now again the headers are not getting written to the HTTP header fields?!Alberic
It should work fine according to the src github.com/angular/angular/blob/master/packages/common/http/src/… . I cant help you any further without more information about your issue (code)Sisneros
So in my case I made an mistake by switching headers & params in the list of arguments to a function (since both accepted a json object). Meaning just watch out for mistakes, and HttpHeaders as type is a good practice after all.. Off-topic: when you can use objects everywhere, don't use TypeScript but VanillaJS.Veer
Why have headers and requests been made immutable? angular.io/guide/http#immutabilityMt
I am using Angular 6. After setting headers also, I am getting Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:4200' is therefore not allowed access. The response had HTTP status code 403. properties.component.ts:23 GOT ERROR:- on console. Can someone please suggest any solution?Hedgehog
I have already tried many methods. Changed the syntaxes of HttpHeaders values. Also checked angular.io. I am able to make API call and get the response if there is no AUTH. I am getting the above error in case of BASIC authentication.Hedgehog
As an important update, as of Angular 6.1.7, you cant use .set() eitherCharmainecharmane
@Charmainecharmane Its still part of the public API angular.io/api/common/http/HttpHeaders#setSisneros
@Sisneros so is .append() but they only work when chained. new HttpDeaders().set() works but let header = new HttpHeaders(); header.set() doesntCharmainecharmane
@Charmainecharmane Both append and set return new instances with the changes applied, as I explain in my answer. How is that related to your previous comment? I think you should remove your comment, as you are making an incorrect assertion.Sisneros
@Sisneros i wont remove my comment as it will help others, you either need to pass the headers into the HttpHeader constructor or call .set() or .append() directly from the new HttpHeader()Charmainecharmane
lol thats exactly what I described in my answer. Whatever, just notice that "as of 6.1.7, you cant uset .set()" is an wrong assertion, or poorly explained.Sisneros
@Sisneros ill rephrase, you cant use .set() and .append() without it being direct onto the constructor methodCharmainecharmane
Silly to make it not behave like developer.mozilla.org/en-US/docs/Web/API/Headers/appendHoneyhoneybee
option const headers = new HttpHeaders({'Content-Type':'application/json; charset=utf-8'}); doesn't work, at least on Angular 9 my implementation : let headers = new HttpHeaders().set('Content-Type','text/xml;charset=UTF-8').set...Ephesus
F
32

To add multiples params or headers you can do the following:

constructor(private _http: HttpClient) {}

//....

const url = `${environment.APP_API}/api/request`;

let headers = new HttpHeaders().set('header1', hvalue1); // create header object
headers = headers.append('header2', hvalue2); // add a new header, creating a new object
headers = headers.append('header3', hvalue3); // add another header

let params = new HttpParams().set('param1', value1); // create params object
params = params.append('param2', value2); // add a new param, creating a new object
params = params.append('param3', value3); // add another param 

return this._http.get<any[]>(url, { headers: headers, params: params })
Faretheewell answered 11/11, 2017 at 22:20 Comment(2)
This method does not seem to work either. I mean, you can add the headers, and they will show in the lazyUpdate property, but eventually it will crash with the CreateListFromArrayLike exception when making the request effective by subscribing to it.Botswana
To add multiple headers use: headers:HttpHeaders = new HttpHeaders({ 'Application-Id': this.appId, "REST-API-Key": this.apiKey, "Content-Type": "application/json" });Friarbird
P
16

set http headers like below in your http request

return this.http.get(url, { headers: new HttpHeaders({'Authorization': 'Bearer ' + token})
 });
Piscatory answered 20/12, 2017 at 4:26 Comment(0)
U
10

I struggled with this for a long time. I am using Angular 6 and I found that

let headers = new HttpHeaders();
headers = headers.append('key', 'value');

did not work. But what did work was

let headers = new HttpHeaders().append('key', 'value');

did, which makes sense when you realize they are immutable. So having created a header you can't add to it. I haven't tried it, but I suspect

let headers = new HttpHeaders();
let headers1 = headers.append('key', 'value');

would work too.

Uncommunicative answered 27/8, 2018 at 4:17 Comment(1)
Your first attempt should work, you're assigning the result of the append to the headers variable. Right now your explanation doesn't make any sense, specially your last guess that adding a let may fix itHoneyhoneybee
C
8

I was with Angular 8 and the only thing which worked for me was this:

  getCustomHeaders(): HttpHeaders {
    const headers = new HttpHeaders()
      .set('Content-Type', 'application/json')
      .set('Api-Key', 'xxx');
    return headers;
  }
Catbird answered 12/10, 2019 at 11:3 Comment(0)
B
5

In the manual (https://angular.io/guide/http) I read: The HttpHeaders class is immutable, so every set() returns a new instance and applies the changes.

The following code works for me with angular-4:

 return this.http.get(url, {headers: new HttpHeaders().set('UserEmail', email ) });
Broeder answered 20/11, 2017 at 13:35 Comment(0)
A
5

First, you need to add HttpHeaders with HttpClient

import { HttpClient,HttpHeaders  } from '@angular/common/http';

your constructor should be like this.

constructor(private http: HttpClient) { }

then you can use like this

   let header = new HttpHeaders({ "Authorization": "Bearer "+token});

   const requestOptions = {  headers: header};                                                                                                                                                                            

    return this.http.get<any>(url, requestOptions)
        .toPromise()
        .then(data=> {
            //...
            return data;
    });
Akeylah answered 27/8, 2020 at 6:0 Comment(1)
how you get the token?Electrostatics
G
0

In my legacy app Array.from of prototype js was conflicting with angular's Array.from that was causing this problem. I resolved it by saving angular's Array.from version and reassigning it after prototype load.

Guimpe answered 31/1, 2019 at 23:26 Comment(0)
M
0

I was struggling with this as well. I used an interceptor, it captures the response headers, then clone the headers(since headers are immutable objects) and then sends the modified headers. https://angular.io/guide/http#intercepting-requests-and-responses

Mosenthal answered 22/2, 2021 at 10:8 Comment(0)
H
-2

Angular 8 HttpClient Service example with Error Handling and Custom Header

    import { Injectable } from '@angular/core';
    import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
    import { Student } from '../model/student';
    import { Observable, throwError } from 'rxjs';
    import { retry, catchError } from 'rxjs/operators';

    @Injectable({
      providedIn: 'root'
    })
    export class ApiService {

      // API path
      base_path = 'http://localhost:3000/students';

      constructor(private http: HttpClient) { }

      // Http Options
      httpOptions = {
        headers: new HttpHeaders({
          'Content-Type': 'application/json'
        })
      }

      // Handle API errors
      handleError(error: HttpErrorResponse) {
        if (error.error instanceof ErrorEvent) {
          // A client-side or network error occurred. Handle it accordingly.
          console.error('An error occurred:', error.error.message);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong,
          console.error(
            `Backend returned code ${error.status}, ` +
            `body was: ${error.error}`);
        }
        // return an observable with a user-facing error message
        return throwError(
          'Something bad happened; please try again later.');
      };


      // Create a new item
      createItem(item): Observable<Student> {
        return this.http
          .post<Student>(this.base_path, JSON.stringify(item), this.httpOptions)
          .pipe(
            retry(2),
            catchError(this.handleError)
          )
      }

      ....
      ....

enter image description here

Check complete example tutorial here

Holophytic answered 7/8, 2019 at 15:50 Comment(3)
Is it me or is this kinda overkill for the question asked?Propose
This isn't attempting to answer OPs question. Its just a bunch of code with no explanation whatsoever.Sisneros
This is not even close to context. It looks like self-promotion.Eolanda

© 2022 - 2024 — McMap. All rights reserved.