mirror of
https://github.com/tenrok/axios.git
synced 2026-06-17 19:21:29 +03:00
Fixed toFormData regression bug (unreleased) with Array-like objects serialization; (#4714)
Added `toURLEncodedForm` helper; Added automatic payload serialization to `application/x-www-form-urlencoded` to have parity with `multipart/form-data`; Added test of handling `application/x-www-form-urlencoded` body by express.js; Updated README.md; Added missed param in JSDoc; Fixed hrefs in README.md; Co-authored-by: Jay <jasonsaayman@gmail.com>
This commit is contained in:
+19
-10
@@ -5,6 +5,7 @@ var normalizeHeaderName = require('../helpers/normalizeHeaderName');
|
||||
var AxiosError = require('../core/AxiosError');
|
||||
var transitionalDefaults = require('./transitional');
|
||||
var toFormData = require('../helpers/toFormData');
|
||||
var toURLEncodedForm = require('../helpers/toURLEncodedForm');
|
||||
|
||||
var DEFAULT_CONTENT_TYPE = {
|
||||
'Content-Type': 'application/x-www-form-urlencoded'
|
||||
@@ -71,18 +72,26 @@ var defaults = {
|
||||
}
|
||||
|
||||
var isObjectPayload = utils.isObject(data);
|
||||
var contentType = headers && headers['Content-Type'];
|
||||
|
||||
var contentType = headers && headers['Content-Type'] || '';
|
||||
var isFileList;
|
||||
|
||||
if ((isFileList = utils.isFileList(data)) || (isObjectPayload && contentType === 'multipart/form-data')) {
|
||||
var _FormData = this.env && this.env.FormData;
|
||||
return toFormData(
|
||||
isFileList ? {'files[]': data} : data,
|
||||
_FormData && new _FormData(),
|
||||
this.formSerializer
|
||||
);
|
||||
} else if (isObjectPayload || contentType === 'application/json') {
|
||||
if (isObjectPayload) {
|
||||
if (contentType.indexOf('application/x-www-form-urlencoded') !== -1) {
|
||||
return toURLEncodedForm(data).toString();
|
||||
}
|
||||
|
||||
if ((isFileList = utils.isFileList(data)) || contentType.indexOf('multipart/form-data') !== -1) {
|
||||
var _FormData = this.env && this.env.FormData;
|
||||
|
||||
return toFormData(
|
||||
isFileList ? {'files[]': data} : data,
|
||||
_FormData && new _FormData(),
|
||||
this.formSerializer
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (isObjectPayload || contentType.indexOf('application/json') !== -1) {
|
||||
setContentTypeIfUnset(headers, 'application/json');
|
||||
return stringifySafely(data);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ function encode(val) {
|
||||
*
|
||||
* @param {string} url The base of the url (e.g., http://www.google.com)
|
||||
* @param {object} [params] The params to be appended
|
||||
* @param {?object} paramsSerializer
|
||||
* @returns {string} The formatted url
|
||||
*/
|
||||
module.exports = function buildURL(url, params, paramsSerializer) {
|
||||
|
||||
+22
-20
@@ -20,6 +20,20 @@ function renderKey(path, key, dots) {
|
||||
}).join(dots ? '.' : '');
|
||||
}
|
||||
|
||||
function convertValue(value) {
|
||||
if (value === null) return '';
|
||||
|
||||
if (utils.isDate(value)) {
|
||||
return value.toISOString();
|
||||
}
|
||||
|
||||
if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
|
||||
return typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function isFlatArray(arr) {
|
||||
return utils.isArray(arr) && !arr.some(isVisitable);
|
||||
}
|
||||
@@ -64,21 +78,6 @@ function toFormData(obj, formData, options) {
|
||||
throw new TypeError('visitor must be a function');
|
||||
}
|
||||
|
||||
function convertValue(value) {
|
||||
if (value === null) return '';
|
||||
|
||||
if (utils.isDate(value)) {
|
||||
return value.toISOString();
|
||||
}
|
||||
|
||||
if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
|
||||
return typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {*} value
|
||||
@@ -88,7 +87,7 @@ function toFormData(obj, formData, options) {
|
||||
* @returns {boolean} return true to visit the each prop of the value recursively
|
||||
*/
|
||||
function defaultVisitor(value, key, path) {
|
||||
var arr;
|
||||
var arr = value;
|
||||
|
||||
if (value && !path && typeof value === 'object') {
|
||||
if (utils.endsWith(key, '{}')) {
|
||||
@@ -96,7 +95,10 @@ function toFormData(obj, formData, options) {
|
||||
key = metaTokens ? key : key.slice(0, -2);
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
value = JSON.stringify(value);
|
||||
} else if (!utils.isPlainObject(value) && (arr = utils.toArray(value)) && isFlatArray(arr)) {
|
||||
} else if (
|
||||
(utils.isArray(value) && isFlatArray(value)) ||
|
||||
(utils.isFileList(value) || utils.endsWith(key, '[]') && (arr = utils.toArray(value))
|
||||
)) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
key = removeBrackets(key);
|
||||
|
||||
@@ -138,7 +140,7 @@ function toFormData(obj, formData, options) {
|
||||
stack.push(value);
|
||||
|
||||
utils.forEach(value, function each(el, key) {
|
||||
var result = !utils.isUndefined(el) && defaultVisitor.call(
|
||||
var result = !utils.isUndefined(el) && visitor.call(
|
||||
formData, el, utils.isString(key) ? key.trim() : key, path, exposedHelpers
|
||||
);
|
||||
|
||||
@@ -150,8 +152,8 @@ function toFormData(obj, formData, options) {
|
||||
stack.pop();
|
||||
}
|
||||
|
||||
if (!utils.isPlainObject(obj)) {
|
||||
throw new TypeError('data must be a plain object');
|
||||
if (!utils.isObject(obj)) {
|
||||
throw new TypeError('data must be an object');
|
||||
}
|
||||
|
||||
build(obj);
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
var utils = require('../utils');
|
||||
var toFormData = require('./toFormData');
|
||||
var platform = require('../platform/');
|
||||
|
||||
module.exports = function toURLEncodedForm(data) {
|
||||
return toFormData(data, new platform.classes.URLSearchParams(), {
|
||||
visitor: function(value, key, path, helpers) {
|
||||
if (platform.isNode && utils.isBuffer(value)) {
|
||||
this.append(key, value.toString('base64'));
|
||||
return false;
|
||||
}
|
||||
|
||||
return helpers.defaultVisitor.apply(this, arguments);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = (function getURLSearchParams(nativeURLSearchParams) {
|
||||
if (typeof nativeURLSearchParams === 'function') return nativeURLSearchParams;
|
||||
|
||||
function encode(str) {
|
||||
var charMap = {
|
||||
'!': '%21',
|
||||
"'": '%27',
|
||||
'(': '%28',
|
||||
')': '%29',
|
||||
'~': '%7E',
|
||||
'%20': '+',
|
||||
'%00': '\x00'
|
||||
};
|
||||
return encodeURIComponent(str).replace(/[!'\(\)~]|%20|%00/g, function replacer(match) {
|
||||
return charMap[match];
|
||||
});
|
||||
}
|
||||
|
||||
function URLSearchParams() {
|
||||
this.pairs = [];
|
||||
}
|
||||
|
||||
var prototype = URLSearchParams.prototype;
|
||||
|
||||
prototype.append = function append(name, value) {
|
||||
this.pairs.push([name, value]);
|
||||
};
|
||||
|
||||
prototype.toString = function toString() {
|
||||
return this.pairs.map(function each(pair) {
|
||||
return pair[0] + '=' + encode(pair[1]);
|
||||
}, '').join('&');
|
||||
};
|
||||
|
||||
return URLSearchParams;
|
||||
})(URLSearchParams);
|
||||
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
isBrowser: true,
|
||||
classes: {
|
||||
URLSearchParams: require('./classes/URLSearchParams')
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = require('./node/');
|
||||
@@ -0,0 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var url = require('url');
|
||||
|
||||
module.exports = url.URLSearchParams;
|
||||
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
isNode: true,
|
||||
classes: {
|
||||
URLSearchParams: require('./classes/URLSearchParams')
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user