defaults(默认配置)和mergeConfig(合并config方法)


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
总得来说前端只能设置请求头,响应头只能客户端设置


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM