axios是怎么做到适配xhr和http的
前言
我们在使用axios的时候是不需要判断这个环境和指定发送的方法的,但是它既可以发送浏览器环境下xhr请求,也可以发送node环境下http请求,就来看一下这是怎么实现的。
基础结构
——lib
|——adpters
|—— adapters.js
|—— http.js
|—— xhr.js
|——cancel
|——CanceledError.js
|——CancelToken.js
|——isCancel.js
|——core
|——Axios.js
|——AxiosError.js
|——AxiosHeader.js
|——buildFullpath.js
|——despatchRequest.js
|——InterceptorManager.js
|——mergeConfig.js
|——settle.js
|——transformData.js
|——defaults
|——index.js
|——transitional
|——env
|——helper
|——plaform
|——axios.js
|——utils.js
发送请求
通常我们使用axios发送请求使用的方法就是 axios.request(configOrUrl,config) 或者 axios.get(url,config)
axios是Axios的实例,在Axios类中,有一个很重要的方法 request(), 其他的get,post 等方法都是依赖request方法改造来的
首先,我们看一下Axios类中有什么
class Axios {
constructor(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
request(config){
promise = dispatchRequest.call(this, newConfig);
}
getUri(config){}
}
request()是 发送请求的方法,之后get(),post()等方法封装request()并挂载在Axios原型对象中。从而可以通过 axios.get() 来发送请求
request()方法处理请求头,拦截请求,发送请求,拦截响应。我们忽略拦截器,不妨直接看 dispatchRequest()
export default function dispatchRequest(config) {
const adapter = adapters.getAdapter(config.adapter || defaults.adapter);
return adapter(config).then(function onAdapterResolution(response) {
}
}
dispatchRequest() 转换请求数据、 选择adapter并发送请求、 转换响应数据。
这个adapter是什么呢?
是适配器。发送数据有多种环境,我们常用的就是node环境和浏览器环境,但是我们在使用axios时是不用区分是何种环境的,原因就在于axios做了适配。
通过adapters.getAdapter() 得到一个函数,这个函数才是真正发送请求的地方。实际上可以返回的函数有两个
- httpAdapter
- xhrAdapter
xhr适配器
const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined';
export default isXHRAdapterSupported && function (config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
let request = new XMLHttpRequest();
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
function onload(){}
request.send(requestData || null);
}
http适配器
const isHttpAdapterSupported = typeof process !== 'undefined' && utils.kindOf(process) === 'process';
export default isHttpAdapterSupported && function httpAdapter(config) {
return new Promise(async function dispatchHttpRequest(resolvePromise, rejectPromise) {
const options = {... };
req = transport.request(options, function handleResponse(res){
const response = {...};
})
if (utils.isStream(data)) {
data.pipe(req);
}else {
req.end()
}
}
调用适配器
适配器模式讲究的就是一个兼容,从外部来看我们并不关心它具体是什么请求。具体是怎么实现的呢?
发送请求的大致过程

\\ lib/adapters/adapter
const knownAdapters = {
http: httpAdapter,
xhr: xhrAdapter
}
\\ lib\core\diaptchRuest
function dispactchRequest(){
const adapter = adapters.getAdapter(config.adapter || defaults.adapter);
return adpater(config).then(){...}
}
getAdapter() 的具体实现
getAdapter: (adapters) => {
adapters = utils.isArray(adapters) ? adapters : [adapters];
for (let i = 0; i < length; i++) {
nameOrAdapter = adapters[i];
if (!isResolvedHandle(nameOrAdapter)) {
adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()];
}
if (adapter) {
break;
}
}
}
getAdapter 的实现就是传入适配器列表,找到最先可以执行的适配器,将适配器返回。 默认的适配器列表是 ['xhr','http']从中可以看出xhr的优先级是要比http请求的优先级高的。
总结
- 无论是xhr适配器还是http适配器,都是一个接收config返回promise的函数,结构上是一致的,因此可以通过适配器模式兼容他们,在使用axios的时候就不用考虑是什么环境。
- axios通过判断环境和适配器列表选择适配器,发送相应请求。
如果您觉得这篇文章有帮助,请点个赞吧~
评论
请登录后发表评论
去登录