在Angular HttpClient中添加HTTP头部不会发送该头部,为什么?

246

这是我的代码:

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.');
            }
        }
    );
}

这里是网络调试信息:

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

数据存储在“请求有效载荷”中,但我的服务器没有收到POST值:

print_r($_POST);
Array
(
)

我认为这个错误是由于在POST期间未设置标头造成的,我做错了什么?


是的,谢谢!但是在我的后端没有收到数据之后,我改用了application/x-www-form-urlencoded格式。无论如何,主要问题已经得到回答。 - Frennetix
10个回答

419

新的HttpHeader类的实例是不可变对象。调用类方法将返回一个新实例作为结果。所以基本上,你需要做以下事情:

let headers = new HttpHeaders();
headers = headers.set('Content-Type', 'application/json; charset=utf-8');
或者
const headers = new HttpHeaders({'Content-Type':'application/json; charset=utf-8'});

更新:添加多个标题

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

或者

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

更新:HttpClient头部和参数现在支持接受对象映射

自从5.0.0-beta.6版本以来,现在可以跳过创建HttpHeaders对象并直接传递一个对象映射作为参数。因此现在可以进行以下操作:

http.get('someurl',{
   headers: {'header1':'value1','header2':'value2'}
});

68
有趣。对于我们来自面向对象编程的世界,set 方法名有些误导性。 - tishma
4
如果我想设置多个标头,该怎么办?我已经尝试了链接注释HttpHeaders().set(..).set(..),但是这些标头没有被写入到HTTP标头字段中! - Stefan Falk
4
为什么将请求头和请求体设置为不可变?在Angular中,将HTTP请求头和请求体设置为不可变有很多好处。首先,它可以防止在请求发送之前意外修改这些数据。其次,如果需要进行异步操作,这种不可变性可以确保请求数据在此期间不会被意外更改。最后,由于这些对象是不可变的,它们可以方便地用作缓存键或在应用程序的其他部分共享而不必担心任何副作用。 - Drellgor
重要更新:自Angular 6.1.7起,您也无法使用.set() - mast3rd3mon
2
让它不像 https://developer.mozilla.org/en-US/docs/Web/API/Headers/append 那样运行是很愚蠢的。 - Ruan Mendes
显示剩余11条评论

31

要添加多个参数或标头,您可以执行以下操作:

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 })

2
这种方法似乎也不起作用。我的意思是,你可以添加头信息,它们会显示在lazyUpdate属性中,但最终当订阅请求并使其生效时,它将崩溃并出现CreateListFromArrayLike异常。 - Jago
3
为添加多个标题,请使用以下代码:headers:HttpHeaders = new HttpHeaders({ 'Application-Id': this.appId, "REST-API-Key": this.apiKey, "Content-Type": "application/json" });请注意,此代码中的每个标题均以逗号分隔,并位于大括号内。 - Benson

16

在您的 HTTP 请求中,可以设置如下的 HTTP 标头:

return this.http.get(url, { headers: new HttpHeaders({'Authorization': 'Bearer ' + token})
 });

9

我长期以来都在为此苦恼。我正在使用 Angular 6,我发现

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

没有起作用,但起作用的是什么。
let headers = new HttpHeaders().append('key', 'value');

当你意识到标头是不可变的时,这就解释了为什么需要使用did。因此,创建了一个标头后,您无法向其中添加内容。

我没有尝试过它,但我怀疑
let headers = new HttpHeaders();
let headers1 = headers.append('key', 'value');

也可以起作用。


3
你的第一次尝试应该可以工作,因为你正在将附加的结果分配给headers变量。现在你的解释没有任何意义,特别是你最后的猜测,即添加一个let 可能会修复它。 - Ruan Mendes

8

我使用Angular 8,唯一管用的方法是:

  getCustomHeaders(): HttpHeaders {
    const headers = new HttpHeaders()
      .set('Content-Type', 'application/json')
      .set('Api-Key', 'xxx');
    return headers;
  }

5
在手册(https://angular.io/guide/http)上我看到: HttpHeaders类是不可变的,因此每个set()方法都会返回一个新的实例并应用更改。
以下代码在使用angular-4时适用:
   return this.http.get(url, {headers: new HttpHeaders().set('UserEmail', email ) });

5

首先,您需要使用HttpClient添加HttpHeaders。

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

你的构造函数应该像这样。

constructor(private http: HttpClient) { }

然后你可以像这样使用

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

   const requestOptions = {  headers: header};                                                                                                                                                                            

    return this.http.get<any>(url, requestOptions)
        .toPromise()
        .then(data=> {
            //...
            return data;
    });

你如何获取令牌? - Md. Abu Zaman

0
在我的传统应用程序中,prototype js的Array.from与angular的Array.from发生了冲突,导致了这个问题。我通过保存angular的Array.from版本并在原型加载后重新分配它来解决了这个问题。

0

-2

Angular 8 HttpClient服务示例,包括错误处理自定义标头

    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

查看完整的示例教程在这里


3
这是我还是问题有点过度了? - Ojonugwa Jude Ochalifu
3
这并不是在回答原帖的问题,只是一堆没有任何解释的代码。 - Jota.Toledo
1
这与上下文毫不相干,看起来像是自我推销。 - Aakash Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接