feat(http): automatically set request Content-Type header based on body type

Implement the ability to provide objects as request body. The following use cases
are supported:
* raw objects: a JSON payload is created and the content type set to `application/json`
* text: the text is used as it is and no content type header is automatically added
* URLSearchParams: a form payload is created and the content type set to `application/x-www-form-urlencoded`
* FormData: the object is used as it is and no content type header is automatically added
* Blob: the object is used as it is and the content type set with the value of its `type` property if any
* ArrayBuffer: the object is used as it is and no content type header is automatically added

Closes https://github.com/angular/http/issues/69

Closes #7310
This commit is contained in:
Thierry Templier
2016-02-26 12:25:55 +01:00
committed by Misko Hevery
parent e0c83f669e
commit 0f0a8ade7c
9 changed files with 263 additions and 10 deletions

View File

@ -1,6 +1,8 @@
import {RequestMethod} from './enums';
import {RequestArgs} from './interfaces';
import {Headers} from './headers';
import {ContentType} from './enums';
import {URLSearchParams} from './url_search_params';
import {normalizeMethodName} from './http_utils';
import {isPresent, StringWrapper} from '../src/facade/lang';
@ -53,8 +55,10 @@ export class Request {
headers: Headers;
/** Url of the remote resource */
url: string;
// TODO: support URLSearchParams | FormData | Blob | ArrayBuffer
private _body: string;
/** Body of the request **/
private _body: any;
/** Type of the request body **/
private contentType: ContentType;
constructor(requestOptions: RequestArgs) {
// TODO: assert that url is present
let url = requestOptions.url;
@ -71,6 +75,7 @@ export class Request {
}
}
this._body = requestOptions.body;
this.contentType = this.detectContentType();
this.method = normalizeMethodName(requestOptions.method);
// TODO(jeffbcross): implement behavior
// Defaults to 'omit', consistent with browser
@ -85,4 +90,82 @@ export class Request {
* string.
*/
text(): string { return isPresent(this._body) ? this._body.toString() : ''; }
/**
* Returns the request's body as JSON string, assuming that body exists. If body is undefined,
* return
* empty
* string.
*/
json(): string { return isPresent(this._body) ? JSON.stringify(this._body) : ''; }
/**
* Returns the request's body as array buffer, assuming that body exists. If body is undefined,
* return
* null.
*/
arrayBuffer(): ArrayBuffer {
if (this._body instanceof ArrayBuffer) return <ArrayBuffer>this._body;
throw "The request body isn't an array buffer";
}
/**
* Returns the request's body as blob, assuming that body exists. If body is undefined, return
* null.
*/
blob(): Blob {
if (this._body instanceof Blob) return <Blob>this._body;
if (this._body instanceof ArrayBuffer) return new Blob([this._body]);
throw "The request body isn't either a blob or an array buffer";
}
/**
* Returns the content type of request's body based on its type.
*/
detectContentType() {
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;
}
}
/**
* Returns the request's body according to its type. If body is undefined, return
* null.
*/
getBody(): any {
switch (this.contentType) {
case ContentType.JSON:
return this.json();
case ContentType.FORM:
return this.text();
case ContentType.FORM_DATA:
return this._body;
case ContentType.TEXT:
return this.text();
case ContentType.BLOB:
return this.blob();
case ContentType.ARRAY_BUFFER:
return this.arrayBuffer();
default:
return null;
}
}
}
const noop = function () {};
const w = typeof window == 'object' ? window : noop;
const FormData = w['FormData'] || noop;
const Blob = w['Blob'] || noop;
const ArrayBuffer = w['ArrayBuffer'] || noop;