处理配置选项
我们定义好了默认配置对象,并且把它们跟用户自定义的配置对象合并在了一起,现在是时候使用这些配置项了。
我们先在dispatchRequest.js
中的 dispatchRequest
函数来处理、使用这些配置项
这里面处理的事情非常简单,就是把 headers 里面嵌套的对象,扁平化到 headers 上,减少属性的查找层级
module.exports = function dispatchRequest(config) {
// 确保 headers 存在
config.headers = config.headers || {};
// 压平headers
config.headers = utils.merge(
config.headers.common || {},
config.headers[config.method] || {},
config.headers
);
// 删除headers的以下属性,因为这些属性值为对象,且对象里面的内容已经被压平到headers中去了
utils.forEach(
["delete", "get", "head", "post", "put", "patch", "common"],
function cleanHeaderConfig(method) {
delete config.headers[method];
}
);
// 以下部分代码请参考前面的章节或最后一章提供的参考资料
// ....
};
我们接着在xhr.js
中的 xhrAdapter
函数来处理、使用这些配置项。
首先我们通过 buildFullPath
函数把 baseURL
,跟 url
构建成一个完整的 url
路径。然后通过 buildURL
函数把 config
对象上的 params
对象参数序列化到 url
中。
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
// 请求数据
var requestData = config.data;
// 构造一个xhr对象
var request = new XMLHttpRequest();
// 构建全路径
var fullPath = buildFullPath(config.baseURL, config.url);
// xhrReq.open(method, url, async)
// method: HTTP方法,比如GET、POST
// url: 请求的URL
// async: 表示是否异步执行操作,默认为true
request.open(
config.method.toUpperCase(),
buildURL(fullPath, config.params, config.paramsSerializer),
true
);
});
};
我们在 core
文件下创建 buildFullPath.js
文件,buildFullPath
函数接收两个参数,一个是 baseURL
,一个是 requestedURL
, 我们用 isAbsoluteURL
函数来对 requestedURL
参数作判断,如果该 url
不是绝对路径,则用 combineURLs
函数把 baseURL
跟其组合成新的 url
。
"use strict";
var isAbsoluteURL = require("../helpers/isAbsoluteURL");
var combineURLs = require("../helpers/combineURLs");
/**
* 如果requestedURL不是绝对路径,则组合baseURL和requestedURL来创建新的URL
* 如果是绝对url则直接返回
* @param {string} baseURL 基础url
* @param {string} requestedURL 请求url
* @returns {string} 组合后的完整路径
*/
module.exports = function buildFullPath(baseURL, requestedURL) {
if (baseURL && !isAbsoluteURL(requestedURL)) {
return combineURLs(baseURL, requestedURL);
}
return requestedURL;
};
我们在 helpers
文件夹下创建 isAbsoluteURL.js
文件和 combineURLs.js
文件,分别实现isAbsoluteURL
函数和 combineURLs
函数
"use strict";
/**
* 测试url是否为绝对url
*
* @param {string} url 要测试的url
* @returns {boolean}
*/
module.exports = function isAbsoluteURL(url) {
// 如果url以 "<scheme>://" or "//" 开头,则认为是绝对url
return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
};
"use strict";
/**
* 组合成新的url
*
* @param {string} baseURL 基础url
* @param {string} relativeURL 相对URL
* @returns {string}
*/
module.exports = function combineURLs(baseURL, relativeURL) {
return relativeURL
? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "")
: baseURL;
};
我们在 helpers
文件夹下创建 buildURL.js
文件,来实现 buildURL
函数。该函数做的事情非常简单,就是把 config.params
序列化到 url
上,代码如下
var utils = require("../utils");
// 对参数键值进行编码
function encode(val) {
return encodeURIComponent(val)
.replace(/%3A/gi, ":")
.replace(/%24/g, "$")
.replace(/%2C/gi, ",")
.replace(/%20/g, "+")
.replace(/%5B/gi, "[")
.replace(/%5D/gi, "]");
}
/**
* 序列化params参数到url中
*
* @param {string} url (e.g., http://www.google.com)
* @param {object} [params] 要序列化的params参数
* @returns {string} 格式化后的参数
*/
module.exports = function buildURL(url, params, paramsSerializer) {
/*eslint no-param-reassign:0*/
if (!params) {
return url;
}
var serializedParams;
if (paramsSerializer) {
// 如果开发者自定义了params的序列化参数函数,则使用自定义的函数
serializedParams = paramsSerializer(params);
} else if (utils.isURLSearchParams(params)) {
// 如果params是URLSearchParams类型
serializedParams = params.toString();
} else {
var parts = [];
utils.forEach(params, function serialize(val, key) {
// 值不存在,则忽略该键
if (val === null || typeof val === "undefined") {
return;
}
if (utils.isArray(val)) {
key = key + "[]";
} else {
val = [val];
}
utils.forEach(val, function parseValue(v) {
if (utils.isDate(v)) {
// 值是日期类型,则转换为ISOString
v = v.toISOString();
} else if (utils.isObject(v)) {
// 值是对象类型,则json化
v = JSON.stringify(v);
}
parts.push(encode(key) + "=" + encode(v));
});
});
serializedParams = parts.join("&");
}
if (serializedParams) {
var hashmarkIndex = url.indexOf("#");
// 去掉哈希
if (hashmarkIndex !== -1) {
url = url.slice(0, hashmarkIndex);
}
// url存在'?'则直接拼接上参数,否则在url后添加'?', 再拼接
url += (url.indexOf("?") === -1 ? "?" : "&") + serializedParams;
}
return url;
};
buildURL
函数用到了一些 utils.js
中的辅助函数,我们来实现这些函数
function kindOfTest(type) {
type = type.toLowerCase();
return function isKindOf(thing) {
return kindOf(thing) === type;
};
}
function isObject(val) {
return val !== null && typeof val === "object";
}
var isDate = kindOfTest("Date");
var isURLSearchParams = kindOfTest("URLSearchParams");
module.exports = {
isArray,
forEach: forEach,
merge: merge,
trim: trim,
extend: extend,
isObject: isObject,
isPlainObject: isPlainObject,
isUndefined: isUndefined,
isDate: isDate,
isURLSearchParams: isURLSearchParams,
};