简体   繁体   English

如何告诉Angular 2停止自动设置Content-Type标头?

[英]How can I tell Angular 2 to stop setting Content-Type headers automatically?

I am currently trying to access an API with an Angular 2 (via Ionic 2) app. 我目前正在尝试使用Angular 2(通过Ionic 2)应用程序访问API。 Our laravel backend is set up in such a way that it expects an Accept header with the content-type of the request, and no Content-Type header. 我们的laravel后端的设置方式使得它需要一个包含请求内容类型的Accept标头,而不是Content-Type标头。 Not just an empty Content-Type header, but none at all. 不只是一个空的Content-Type标头,而且根本没有。

So, I am setting up the requisite parameters in Http, omitting Content-Type in the Headers, and that's where the problem starts: Angular 2 apparently can't keep its hands off the Content-Type. 所以,我在Http中设置了必要的参数,在Headers中省略了Content-Type,这就是问题的开始:Angular 2显然无法保持其内容类型。 If I give it an object as the body of the request, it sets the Content-Type to application/json. 如果我给它一个对象作为请求的主体,它将Content-Type设置为application / json。 Which is still understandable. 这仍然是可以理解的。 Then I stringify the Object, which causes Angular to set the Content-Type to text/plain. 然后我对Object进行字符串化,这会导致Angular将Content-Type设置为text / plain。 Attempts, via 尝试,通过

headers = new Header({Accept: 'application/json', Content-Type: undefined});

or 要么

headers.append("Content-Type", undefined);

or any other combination of any header I could imagine that contains an Accept of application/json and nothing else, even headers.set or headers.delete fails, Angular 2 keeps just doing its thing. 或者我想象的任何标题的任何其他组合包含一个接受应用程序/ json而没有别的,甚至headers.set或headers.delete失败,Angular 2继续做它的事情。

Setting Content-Type to undefined was suggested elsewhere, I have also tried to set it to an empty string, to application/json when passing in the stringified JSON, Angular just doesn't give a flying f... about what I want. 在其他地方建议将Content-Type设置为undefined,我也尝试将其设置为空字符串,在传递字符串化的JSON时将其设置为application / json,Angular只是不会给出我想要的内容。 Is there a way to turn this automatism off? 有没有办法扭转这种自动化? Am I still doing something wrong (I am importing Headers, which, aka the lack thereof, was a problem elsewhere, so that should be out)? 我还在做错什么(我正在导入Headers,其中也就是缺少它,在其他地方是一个问题,所以应该出来)?

Here comes the code: 代码如下:

import { Injectable, Inject } from '@angular/core';

import { Http, Headers, RequestOptions } from '@angular/http';
import 'rxjs/add/operator/toPromise';

import { ConfsService } from '../confs/confs.service';

import { ApiRequestBody }   from './api.request.body';

@Injectable()
export class ApiService {
    constructor(public confs: ConfsService, private apiRequestBody: ApiRequestBody, private http: Http) {

    post (method: string, data: any):Promise<any> {
        const api = this.confs.get().api;
        const url = api['server'] + "" + api[method];
        let allParams = this.apiRequestBody.toJSON(data);
        let body = JSON.stringify(allParams);
        let headers = new Headers({
            'Accept': 'application/json',
            'Content-Type': undefined,
        });
        let options = new RequestOptions({ headers: headers });     
        let obj = this.http.post(url, body, options).toPromise();
        return obj;
    }
}

The ConfsService just gets a couple of configuration parameters, aka the api server URL, and ApiRequestBody gets a service that creates a standard set of parameters that the API needs to even look at the request, in addition to those that are passed in via the data parameter (which is then merged into the standard parameters in the toJSON method) - no rocket science. ConfsService只获取一些配置参数,即api服务器URL,ApiRequestBody获取一个服务,该服务创建API甚至需要查看请求的一组标准参数,以及通过数据传递的参数。参数(然后合并到toJSON方法中的标准参数) - 没有火箭科学。 And I am doing a toPromise() because I find a promise in this particular case easier to handle. 我正在做一个toPromise()因为我发现在这种特殊情况下的承诺更容易处理。

After digging through Angular source code I have concluded that this is not possible. 在深入研究Angular源代码后,我得出结论认为这是不可能的。 See static_request.ts ( https://github.com/angular/angular/blob/5293794316cc1b0f57d5d88b3fefdf6ae29d0d97/packages/http/src/static_request.ts ), it will first check if you have manually set the headers to a specific string, and undefined or empty string will fall through to the detectContentTypeFromBody function which will only set ContentType.NONE if your request body is null. 请参阅static_request.ts( https://github.com/angular/angular/blob/5293794316cc1b0f57d5d88b3fefdf6ae29d0d97/packages/http/src/static_request.ts ),它将首先检查您是否已手动将标头设置为特定字符串,并且未定义或者空字符串将落入detectContentTypeFromBody函数,该函数仅在您的请求正文为空时才设置ContentType.NONE。

  /**
   * Returns the content type enum based on header options.
   */
  detectContentType(): ContentType {
    switch (this.headers.get('content-type')) {
      case 'application/json':
        return ContentType.JSON;
      case 'application/x-www-form-urlencoded':
        return ContentType.FORM;
      case 'multipart/form-data':
        return ContentType.FORM_DATA;
      case 'text/plain':
      case 'text/html':
        return ContentType.TEXT;
      case 'application/octet-stream':
        return this._body instanceof ArrayBuffer ? ContentType.ARRAY_BUFFER : ContentType.BLOB;
      default:
        return this.detectContentTypeFromBody();
    }
  }

  /**
   * Returns the content type of request's body based on its type.
   */
  detectContentTypeFromBody(): ContentType {
    if (this._body == null) {
      return ContentType.NONE;
    } else if (this._body instanceof URLSearchParams) {
      return ContentType.FORM;
    } else if (this._body instanceof FormData) {
      return ContentType.FORM_DATA;
    } else if (this._body instanceof Blob) {
      return ContentType.BLOB;
    } else if (this._body instanceof ArrayBuffer) {
      return ContentType.ARRAY_BUFFER;
    } else if (this._body && typeof this._body === 'object') {
      return ContentType.JSON;
    } else {
      return ContentType.TEXT;
    }
  }

Update: 更新:

It looks like it actually is possible by extending Request and overloading the detectContentType function to return 0. This requires accessing non public code though so it could break in the future: 看起来它实际上可以通过扩展Request并重载detectContentType函数来返回0.这需要访问非公共代码,因为它可能在以后中断:

import {Http, Headers, RequestOptions, RequestMethod, Request, BaseRequestOptions, Response} from '@angular/http';
import { ContentType } from '@angular/http/src/enums';
import { RequestArgs } from '@angular/http/src/interfaces';

class NoContentRequest extends Request {
  constructor(args: RequestArgs) {
    super(args);
  }
  detectContentType(): ContentType {
    return 0;
  }
}

const headers = new Headers({Accept: 'application/json'});

const request  = new NoContentRequest({
  method: RequestMethod.Post,
  url: 'https://www.example.com/example',
  responseType: ResponseContentType.Json,
  headers: headers,
  body: body
});

this._http.request(request)
  .catch((error: Response | any) => { console.error(error); return Observable.throw(error); })
  .first()
  .subscribe();

I think the better way is to delete 'Content-Type' header from request. 我认为更好的方法是从请求中删除“Content-Type”标头。

ie

     this.http.post(apiUrl, request, {
         headers: new HttpHeaders().delete('Content-Type')
     });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM