Axios-API源码字典

189 阅读5分钟

1、axios(config)

  • 使用
// 发送 POST 请求
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});
  • 核心源码
/* 1 axios */
/**
 * 创建Axios实例
 * @param {Object} defaultConfig 实例的默认配置
 * @return {Axios} Axios的新实例
 */
function createInstance(defaultConfig) {
  var context = new Axios(defaultConfig);
  /* 程序员调用的axios.request(config) */ 
  var instance = bind(Axios.prototype.request, context);
  // 复制axios的原型到实例上
  utils.extend(instance, Axios.prototype, context);
  // 将上下文复制到实例
  utils.extend(instance, context);
  return instance;
}
//创建要导出的默认实例
var axios = createInstance(defaults);

/* 4 Axios */
/**
 * 发送请求
 * @param {Object} config 此请求的特定配置(merged with this.defaults)
 */
Axios.prototype.request = function request(config) {
  if (typeof config === 'string') {
    // eg: axios.request("localhost://xxx")
    config = arguments[1] || {};
    config.url = arguments[0];
  } else {
    config = config || {};
  }
  // 合并默认config和程序员传递的config
  config = mergeConfig(this.defaults, config);
  // 设置config的method,转换为小写
  if (config.method) {
    config.method = config.method.toLowerCase();
  } else if (this.defaults.method) {
    config.method = this.defaults.method.toLowerCase();
  } else {
    // 默认为get请求
    config.method = 'get';
  }

  // 连接拦截器中间件
  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);
  
  // 添加请求前拦截
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  // 接收结果前拦截
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });
  
  // dispatchReuest发送请求永远会在数组的中间
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }

  return promise;
};
	

2、axios(url[, config])

  • 使用
// 发送 GET 请求(默认的方法)
axios('/user/12345');
  • 核心源码
/* 4 Axios */
Axios.prototype.request = function request(config) {
  if (typeof config === 'string') {
    // eg: axios.request("localhost://xxx")
    config = arguments[1] || {};
    config.url = arguments[0];
  } else {
    config = config || {};
  }
  // ...
}

3、请求方法别名

  • axios.request(config)
  • axios.get(url[, config])
  • axios.delete(url[, config])
  • axios.head(url[, config])
  • axios.options(url[, config])
  • axios.post(url[, data[, config]])
  • axios.put(url[, data[, config]])
  • axios.patch(url[, data[, config]])

注意:在使用别名方法时, url、method、data 这些属性都不必在配置中指定。

  • 核心源码
/* 4 Axios */
// 为支持的请求方法提供别名 内部实现都是调用Axios.prototype.request方法
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
	});

4、axios.all(iterable)

  • 核心源码
/* 1 axios */
// 全部暴露/扩散
axios.all = function all(promises) {
  return Promise.all(promises);
};

5、axios.spread(callback)

  • 核心源码
/* 25 spread */
/***/ (function(module, exports) {
	module.exports = function spread(callback) {
	  return function wrap(arr) {
	    return callback.apply(null, arr);
	  };
	};
/***/ })

6、axios.create([config])

  • 使用
const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});
  • 核心源码
/* 1 axios */

/* 程序员调用的axios.create() */
axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};
// 返回的实例可以调用
// axios#request(config)
// axios#get(url[, config])
// axios#delete(url[, config])
// axios#head(url[, config])
// axios#options(url[, config])
// axios#post(url[, data[, config]])
// axios#put(url[, data[, config]])
// axios#patch(url[, data[, config]])

7、响应结构

  • 使用
{
  // `data` 由服务器提供的响应
  data: {},

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 服务器响应的头
  headers: {},

   // `config` 是为请求提供的配置信息
  config: {},
 // 'request'
  // `request` is the request that generated this response
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}
}
  • 核心源码
/* 12 adapter:适配器 */
// response数据
var response = {
  data: responseData,
  status: request.status,
  statusText: request.statusText,
  headers: responseHeaders,
  config: config,
  request: request
};
settle(resolve, reject, response);

/* 13 settle:结束请求*/
'use strict';

var createError = __webpack_require__(14);

/**
 * 基于响应状态解决或拒绝承诺。
 *
 * @param {Function} resolve resolve
 * @param {Function} reject reject
 * @param {object} response 返回值
 */
module.exports = function settle(resolve, reject, response) {
  var validateStatus = response.config.validateStatus;
  if (!validateStatus || validateStatus(response.status)) {
    resolve(response);
  } else {
    reject(createError(
      'Request failed with status code ' + response.status,
      response.config,
      null,
      response.request,
      response
    ));
  }
};

/* 10 defaultConfig */
// 创建axios的默认参数
var defaults = {
  // ...
  // 验证状态 http请求的状态码
  validateStatus: function validateStatus(status) {
    return status >= 200 && status < 300;
  }
};
// ...

8、全局的 axios 默认值

  • 使用
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
  • 核心源码
/* 1 axios */
/**
 * 创建Axios实例
 *
 * @param {Object} defaultConfig 实例的默认配置
 * @return {Axios} Axios的新实例
 */
function createInstance(defaultConfig) {
	var context = new Axios(defaultConfig);
  // ...
  // 将上下文复制到实例
  utils.extend(instance, context);
  return instance;
}

/* 4 Axios */
/**
 * Axios构造函数
 *
 * @param {Object} instanceConfig 实例的默认配置
 */
function Axios(instanceConfig) {
  this.defaults = instanceConfig;
  // ...
}

9、拦截器

在请求或响应被 then 或 catch 处理前拦截它们。

  • 使用
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
  // 在发送请求之前做些什么
  return config;
}, function (error) {
  // 对请求错误做些什么
  return Promise.reject(error);
});

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
  // 对响应数据做点什么
  return response;
}, function (error) {
  // 对响应错误做点什么
  return Promise.reject(error);
});

如果你想在稍后移除拦截器,可以这样:

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
  • 核心源码
/* 4 Axios */
/**
 * 发送请求
 * @param {Object} config 此请求的特定配置(merged with this.defaults)
 */
Axios.prototype.request = function request(config) {
  // ...
  // 连接拦截器中间件
  var chain = [dispatchRequest, undefined];
  var promise = Promise.resolve(config);
  
  // 添加请求前拦截
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });
  // 接收结果前拦截
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });
  
  // dispatchReuest发送请求永远会在数组的中间
  while (chain.length) {
    promise = promise.then(chain.shift(), chain.shift());
  }
	
	return promise;
}

/* 6 InterceptorManager:拦截器 */
'use strict';

var utils = __webpack_require__(2);

function InterceptorManager() {
  this.handlers = [];
}

/**
 * 向堆栈添加一个新的拦截器
 *
 * @param {Function} fulfilled 处理“then”for a“Promise”的函数`
 * @param {Function} rejected 为一个承诺处理“拒绝”的函数`
 *
 * @return {Number} 用于稍后删除拦截器的ID
 */
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected
  });
  return this.handlers.length - 1; // 返回数组的索引,便于移除
};

/**
 * 从堆栈中移除拦截器
 *
 * @param {Number} id 使用返回的ID
 */
InterceptorManager.prototype.eject = function eject(id) {
  if (this.handlers[id]) {
    this.handlers[id] = null;
  }
};

/**
 * 迭代所有注册的拦截器
 *
 * 此方法对于跳过任何可能已变为“null”并调用“eject”的侦听器特别有用。
 *
 * @param {Function} fn 为每个拦截器调用的函数
 */
InterceptorManager.prototype.forEach = function forEach(fn) {
  utils.forEach(this.handlers, function forEachHandler(h) {
    if (h !== null) {
      fn(h);
    }
  });
};

module.exports = InterceptorManager;

10、取消

  • 使用
const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function(thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
     // 处理错误
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
  • 核心源码
/* 24 CancelToken */
/**
 * “CancelToken”是可用于请求取消操作的对象。
 *
 * @class
 * @param {Function} executor The executor function.
 */
function CancelToken(executor) {
  if (typeof executor !== 'function') {
    throw new TypeError('executor must be a function.');
  }

  var resolvePromise;
  this.promise = new Promise(function promiseExecutor(resolve) {
    resolvePromise = resolve;
  });

  var token = this;
  executor(function cancel(message) {
    if (token.reason) {
      // 已请求取消
      return;
    }

    token.reason = new Cancel(message);
    resolvePromise(token.reason);
  });
}

/**
 * 返回一个对象,该对象包含一个新的“CancelToken”和一个在调用时取消“CancelToken”的函数。
 */
CancelToken.source = function source() {
  var cancel;
  var token = new CancelToken(function executor(c) {
    cancel = c;
  });
  return {
    token: token,
    cancel: cancel 
    // cancel()执行时,取消请求;配合
    // config.cancelToken.promise.then(function onCanceled(cancel) {
    // 	if (!request) {
    // 		return;
    // 	}

    // 	request.abort();
    // 	reject(cancel);
    // 	// 清理请求
    // 	request = null;
    // });
    // 使用。
    // config.cancelToken.promise.then会在cancel()执行时,触发resolvePromise Promise.resolve函数后,再执行
    // 所以,cancel()不执行时,不会取消请求
  };
};

/* 23 Cancel:取消*/	
	/**
	 * “Cancel”是取消操作时引发的对象。
	 *
	 * @class
	 * @param {string=} message The message.
	 */
	function Cancel(message) {
	  this.message = message;
	}
	
/* 12 adapter:适配器 */
if (config.cancelToken) {
  // 处理取消
  config.cancelToken.promise.then(function onCanceled(cancel) {
    if (!request) {
      return;
    }

    request.abort();
    reject(cancel);
    // 清理请求
    request = null;
  });
}

附录: github.com/fanqiewa/Ax…