实现数据转换器2
我们在defaults
目录下创建transitional.js
文件,默认导出transitional配置对象
module.exports = {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
};
我们在helpers
目录下创建normalizeHeaderName.js
文件,并在里面实现normalizeHeaderName
函数,该函数的作用就是标准化请求头字段,如把 content-type
标准化为 Content-Type
'use strict';
var utils = require('../utils');
module.exports = function normalizeHeaderName(headers, normalizedName) {
// 遍历所有请求头
utils.forEach(headers, function processHeader(value, name) {
// 找到需要处理的请求头字段
if (name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()) {
// 添加标准的请求头字段
headers[normalizedName] = value;
// 删掉原先不规范的请求头字段
delete headers[name];
}
});
};
我们在defaults
目录下创建env
目录,在该目录里面创建FormData.js
文件,
文件的代码非常简单,就是加载一个npm包
module.exports = require('form-data');
我们在helpers
目录创建toFormData.js
文件,在该文件实现toFormData
函数。
'use strict';
var utils = require('../utils');
/**
* 把 data 转换到 FormData
* @param {Object} obj data数据
* @param {?Object} [formData] formData对象
* @returns {Object}
**/
function toFormData(obj, formData) {
formData = formData || new FormData();
var stack = [];
// 对值进行转换
function convertValue(value) {
if (value === null) return '';
// 日期类型,需转为ISOString
if (utils.isDate(value)) {
return value.toISOString();
}
// buffer或类型数组,转为Blob类型,我们在这只实现浏览器部分,node部分忽略
if (utils.isArrayBuffer(value) || utils.isTypedArray(value)) {
return new Blob([value])
}
return value;
}
// parentKey是父键,比如 {a: {b: 'v'}}, a就是{b: 'v'}的parentKey
function build(data, parentKey) {
if (utils.isPlainObject(data) || utils.isArray(data)) {
// 循环引用,比如data的属性值引用了data本身:const data = {}, data.key = data
if (stack.indexOf(data) !== -1) {
throw Error('Circular reference detected in ' + parentKey);
}
// 类似于锁的作用,用于处理循环引用
stack.push(data);
utils.forEach(data, function each(value, key) {
if (utils.isUndefined(value)) return;
var fullKey = parentKey ? parentKey + '.' + key : key;
var arr;
if (value && !parentKey && typeof value === 'object') {
if (utils.endsWith(key, '{}')) {
// key以{}结尾,则对值进行stringify
value = JSON.stringify(value);
} else if (utils.endsWith(key, '[]') && (arr = utils.toArray(value))) {
// key以[]结尾,通过utils.toArray把value转为数组,比如value可能是文件列表
// 然后把数组里的值依次添加到formData
arr.forEach(function(el) {
!utils.isUndefined(el) && formData.append(fullKey, convertValue(el));
});
return;
}
}
// 对值进行递归处理,假如value也是个纯对象,这样就可把纯对象里的值也添加到formData
build(value, fullKey);
});
stack.pop();
} else {
formData.append(parentKey, convertValue(data));
}
}
build(obj);
return formData;
}
module.exports = toFormData;
我们接着实现 utils.js
中的辅助函数
var toString = Object.prototype.toString;
// 判断值是否是函数
function isFunction(val) {
return toString.call(val) === '[object Function]';
}
// 判断值是否是ArrayBuffer类型
var isArrayBuffer = kindOfTest('ArrayBuffer')
// 判断值是否是string类型
function isString(val) {
return typeof val === "string";
}
// 判断值是否是文件类型
var isFile = kindOfTest('File');
//判断值是否是Blob类型
var isBlob = kindOfTest('Blob');
// 判断值是否是Stream类型
function isStream(val) {
return isObject(val) && isFunction(val.pipe);
}
// 判断值是否是URLSearchParams类型
var isURLSearchParams = kindOfTest('URLSearchParams')
// 判断值是否是文件列表类型
var isFileList = kindOfTest('FileList')
// 判断值是否是FormData类型
function isFormData(thing) {
var pattern = '[object FormData]';
return thing && (
(typeof FormData === 'function' && thing instanceof FormData) ||
toString.call(thing) === pattern ||
(isFunction(thing.toString) && thing.toString() === pattern)
);
}
// 判断值是否是Buffer类型
function isBuffer(val) {
return (
val !== null &&
!isUndefined(val) &&
val.constructor !== null &&
!isUndefined(val.constructor) &&
typeof val.constructor.isBuffer === "function" &&
val.constructor.isBuffer(val)
);
}
// 判断值是否是ArrayBufferView类型
function isArrayBufferView(val) {
var result;
if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
result = ArrayBuffer.isView(val);
} else {
result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
}
return result;
}
// 判断值是否是类型数组
var isTypedArray = (function(TypedArray) {
// eslint-disable-next-line func-names
return function(thing) {
return TypedArray && thing instanceof TypedArray;
};
})(typeof Uint8Array !== 'undefined' && Object.getPrototypeOf(Uint8Array));
/*
* 判断一个字符串是否以指定的字符结尾
* @param {String} str 字符串
* @param {String} searchString 是否以这个字符结尾
* @param {Number} [position= 0] 指定结尾的位置
* @returns {boolean}
*/
function endsWith(str, searchString, position) {
str = String(str);
if (position === undefined || position > str.length) {
position = str.length;
}
position -= searchString.length;
var lastIndex = str.indexOf(searchString, position);
return lastIndex !== -1 && lastIndex === position;
}
// 把like object 转化为数组,e.g. {0: 'a', length: 1}
function toArray(thing) {
if (!thing) return null;
var i = thing.length;
if (isUndefined(i)) return null;
var arr = new Array(i);
while (i-- > 0) {
arr[i] = thing[i];
}
return arr;
}