axios学习笔记defaults(默认配置)和mergeConfig(合并config方法)
找到入口文件
axios/lib/axios.js
...
var mergeConfig = require('./core/mergeConfig');`
var defaults = require('./defaults')`
...
学习mergeConfig
axios/lib/core/mergeConfig.js
var utils = require('../utils')//引入公用方法
// 合并 config1 和config2,并将一些默认配置项放到config中
function mergeConfig(config1, config2) {
config2 = config2 || {};
var config = {}
//默认配置参数字段
//从config2中拿到config里的字段
var valueFromConfig2Keys = ['url', 'method', 'params', 'data'];
//合并config1和config2中的这些字段,config2优先
var mergeDeepPropertiesKeys = ['headers', 'auth', 'proxy'];
// 从config2中拿到default的字段
var defaultToConfig2Keys = [
'baseURL', 'url', 'transformRequest', 'transformResponse', 'paramsSerializer',
'timeout', 'withCredentials', 'adapter', 'responseType', 'xsrfCookieName',
'xsrfHeaderName', 'onUploadProgress', 'onDownloadProgress',
'maxContentLength', 'validateStatus', 'maxRedirects', 'httpAgent',
'httpsAgent', 'cancelToken', 'socketPath'
];
//将config2中valueFromConfig2Key里存在的项复制config对象里
utils.forEach(valueFromConfig2Keys, function valueFromConfig2(prop){//prop为valueFromConfig2Keyd中的具体每项的值
if(typeof config2[prop] !== 'undefined'){
config[prop] = config2[prop];
}
})
utils.forEach(mergeDeepPropertiesKeys, function mergeDeepProperties(prop){
if(utils.isObject(config2[prop])){//如果config2[prop]为对象,进行深度合并
config[prop] = utils.deepMerge(config1[prop], config2[prop]);//此处确保了config1[prop]的存在
} else if(typeof config2[prop] != 'undefiend') {//config2[prop]存在且不为对象,直接赋值
config[prop] = config2[prop];
} else if(utils.isObect(config1[prop])){//config2[prop]不存在但config1[prop]存在且为对象
config[prop] = utils.deepMerge(config1[prop]);
} eles {//config2[prop]不存在且config1[prop]不为对象
config[prop] = config1[prop];
}
})
// 从config2中拿到default的字段,如果没有去config1中拿字段
utils.forEach(defaultToConfig2Keys, function defaultToConfig2(prop){
if(typeof config2[prop] !== 'undefined'){
config[prop] = config2[prop];
} else {
config[prop] = config1[prop]
}
})
//合并所有关键字
var axiosKeys = valueFromConfig2Keys.concat(mergeDeepPropeotiesKeys).cancat(defaultToConfig2Key2);
//找出存在config2中不同于默认配置项的项,并加到config上去
var otherKeys = Object.keys(config2).filter(function filterAxiosKeys(key){
return axiosKeys.indexOf(key) === -1
});
utils.forEach(otherKey2, function other(prop){
if(typeof config2[prop] !== 'undefined' || typeof config1[prop] !== 'undefined'){
config[prop] = config2[prop] || config1[prop];
}
})
//返回拼接后的对象
return config;
}
default默认配置
<!-- 默认配置依赖normalizeHeaderName -->
var utils = require('./utils');
var normalizeHeaderName = require('./helpers/normalizeHeaderName');
...
normalizeHeaderName方法
先看normalizeHeaderName方法,默认配置中使用到此方法
var utils = require('../utils')
module.export = function normalizeHeaderName(headers, normalizedName) {
//转化headers中的键值名,如果headers中的键值不等于normalizedName,且字母相同,将heders中的键值换成normalizedName
utils.forEach(heders, function processHeader(value, name){
if(name !== normalizedName && name.toUpperCase() === normalizedName.toUpperCase()){
headers[normalizedName] = value;//添加新键值对
delete headers[name]; //删除原有键值对
}
})
}
配置默认的Content-Type
请求头content-type,用来指定不同格式的请求信息
mediaType,互联网媒体类型,在http协议消息头中,使用content-type表示具体请求中的媒体类型信息
<!--
常见的媒体格式
text/html:html格式
application/json: json格式
application/x-www-form-urlencoded: (表单默认提交数据格式)<form encType="">中默认的encType,form表单中的数据被编码为key/value格式发送到服务器
multipart/form-data: 需要在表单中进行文件上传时设置此格式
-->
var DEFAULT_CONTENT_TYPE = {//默认的Content-Type
'Content-Type': 'application/x-www-form-urlencoded'
}
setContentTypeIfUnset方法
当没有配置Content-Type时设置headers中Content-Type的值
function setContentTypeIfUnset(headers, value){//value为需要设置的Content-Type的值
//当headers存在且heders[Content-Type]不存在
if(!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])){
headers['Content-Type'] = value;
}
}
getDefaultAdapter方法
获取默认的异步请求适配器,由于axios支持浏览器环境和node环境两套环境,两套环境需要不同的适配器
function getDefaultAdaptet(){
var adapter;
if(typeof XMLHttpRequest !== 'undifined'){//当前环境支持XMLHttpRequest对象为浏览器环境
adapter = require('./adapter/xhr');
} else if(typeof process !== 'undefined' && Object.property.toString.call(process) === '[object process]'){//当前环境支持process对象为node环境
adapter = require('./adapter/http');
}
}
定义默认default对象
var default = {
adapter: getDefaultAdapter(),//默认异步请求适配器,允许自定义处理请求,方便测试
//拦截请求数据默认配置,根据数据类型做一定处理,例如设置Content-type
transformRequest:[function transformRequest(data, headers){
normalizeHederName(headers, 'Accept');//大小写处理,防止用户写错
normalizeHederName(headers, 'Content-Type');
if(utils.isFormData(data) || utils.isArrayBuffer(data) || utils.isBuffer(data) || utils.isStream(data) || utils.isFile(data) || utils.isBlob(data)){
return data;
}
if(utils.isArrayBufferView(data)){
return data.buffer;
}
//根据数据类型设置相应的Content-Type
if(utils.isURLSearchParams(data)){
setContentTypeIfUnset(headers, 'application/x-www-form-urlencoded;charset=utf-8')
return data.toString();
}
if(utils.isObject(data)){
setContentTypeIfUnset(headers, 'application/json;chatset=utf-8')
return JSON.stringify(data);
}
return data;
}],
//拦截响应数据默认配置,根据数据类型做一定处理
transformResponse:[function transformResponse(data){
if(typeof data == 'string'){
try{
data = JSON.parse(data);
}catch(e){
}
}
return data;
}],,
timeout: 0, // 请求超时时长
xsrfCookieName:'XSFR-TOKEN',//表示用作xsrf令牌的值的名称
xsrfHeaderName:'X-XSRF-TOKEN',//表示携带xsrf令牌的值的http头的名称
maxContentLength: -1,定义允许的http响应内容的最大大小
validateStatus: function validateStatus(status){//校验请求返回的状态码,状态码在200-300以内请求成功
return status > 200 && status < 300;
}
}
配置default对象的默认headers
//Accept代表客户希望接受的数据类型,一般情况下服务端会根据accept的值,来决定返回数据的类型,并设置response中Content-type的值
default.headers = {
common: {
'Accept': 'application/json, text/plain, */*',
}
}
给headers加上默认方法
<!-- 添加没有数据的方法 -->
utils.forEach(['delete', 'get', 'header'], function forEachMethodNoData(method){
default.headers[method] = {};
})
<!-- 添加有数据的方法 -->
utils.forEach([post', 'put', 'patch'], function forEachMethodNoData(method){
//post put patch 方法需要传递参数,故需要设置传参默认类型
default.headers[method] = utils.merge(DEFAULT_CONTENT_TYPE);
})
总结
js设置的Content-Type为http请求头中request中的Content-type,是告诉服务器客户端要发送的数据的格式,get,delete请求默认无
js设置的Accept为http请求头中request字段,告诉服务器客户端希望接受的数据的格式
一般情况下服务端会设置http请求头中response中的Content-type和request中Accept格式一样,告诉客户端服务端返回的数据格式
服务器可以根据Accept选择不同的格式,选择返回不同的格式,也可以不管Accpet
总得来说前端只能设置请求头,响应头只能客户端设置