Axios
简介
Axios 是一个基于 Promise 的 HTTP 客户端,同时支持浏览器和Node.js. 拥有以下特性:
- 支持浏览器发送AJAX请求
- 支持Node.js发送 HTTP 请求
- 支持Promise
- 拦截请求和响应
- 转换请求和响应的数据
- 取消请求
- 自动转换JSON数据
- 客户端支持XSRF攻击
源码目录结构
源码主要是在lib目录下。lib目录下的目录结构
│ axios.js
│ defaults.js
│ utils.js
│
├───adapters
│ http.js
│ README.md
│ xhr.js
│
├───cancel
│ Cancel.js
│ CancelToken.js
│ isCancel.js
│
├───core
│ Axios.js
│ buildFullPath.js
│ createError.js
│ dispatchRequest.js
│ enhanceError.js
│ InterceptorManager.js
│ mergeConfig.js
│ README.md
│ settle.js
│ transformData.js
│
└───helpers
bind.js
buildURL.js
combineURLs.js
cookies.js
deprecatedMethod.js
isAbsoluteURL.js
isAxiosError.js
isURLSameOrigin.js
normalizeHeaderName.js
parseHeaders.js
README.md
spread.js
取消请求
在看取消请求之前,确保清楚axios中拦截请求是如何实现的,
简介
取消请求,首先针对要发送的请求中产生一个cancel token,然后利用该cancel token取消请求。
axios的HTTP请求是基于promise,所谓取消请求,就是改变promise的状态,由pending状态修改成reject状态
产生cancel token的方式有两种:
CancelToken.source工厂函数. 实际上CancelToken.source工厂函数是对于CancelToken构造函数的封装CancelToken构造函数
axios的cancel token API是基于已被撤销的cancelable promises proposal.
CancelToken.source 工厂函数创建cancel token
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 {
// handle error
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
CancelToken 构造函数传递一个执行程序创建cancel token
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
})
});
// cancel the request
cancel();
cancelable promises proposal
虽然该proposal cancelable promises proposal 已经被撤销,但是学习它,对于了解axios如何实现取消请求还是很有帮助的。
For the one performing asynchronous work, who will accept an already-existing cancel token, there are three relevant APIs:
cancelToken.reason, which returns either undefined if cancelation has not been requested, or an instance of Cancel given the cancelation reason if it hascancelToken.promise, which allows registration for a callback when cancelation is requested, fulfilled with a Cancel instance constructed when calling the associated cancelcancelToken.throwIfRequested(), which will automatically throw the stored Cancel instance if cancelation is requested (or do nothing otherwise)
对于执行的异步工作,它将接受一个已经存在的取消令牌(token),有三个相关的API:
cancelToken.reason,如果没有请求取消,则返回undefined;如果请求了取消,则返回一个Cancel实例,给出取消原因cancelToken.promise允许在请求取消时注册回调函数canceltoken.throwifrequest(),如果请求取消,它将自动的对于存储的实例抛出异常。如果请求不取消,这个操作不会被触发
源码
cancel token
CancelToken.source 工厂函数
CancelToken.source 工厂函数生成的对象
token属性是一个CanelToken的实例cancel属性一个待触发请求的函数
// lib/cancel/CancelToken.js
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
CancelToken.source = function source() {
var cancel;
var token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
触发cancel
执行cancel(), 触发cancel请求了。
// cancel the request
cancel();
返回一个Cancel实例,给出取消原因
token.reason = new Cancel(message);
在请求取消时注册回调函数
this.promise = new Promise(function promiseExecutor(resolve) {
resolvePromise = resolve;
});
executor(function cancel(message) {
...
resolvePromise(token.reason);
});
// lib/adapters/xhr.js
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
对于存储的取消实例抛出异常
// lib/core/dispatchRequest.js
/**
* Throws a `Cancel` if cancellation has been requested.
*/
function throwIfCancellationRequested(config) {
if (config.cancelToken) {
config.cancelToken.throwIfRequested();
}
}
/**
* Dispatch a request to the server using the configured adapter.
*
* @param {object} config The config that is to be used for the request
* @returns {Promise} The Promise to be fulfilled
*/
module.exports = function dispatchRequest(config) {
throwIfCancellationRequested(config);
...
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData(
response.data,
response.headers,
config.transformResponse
);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
reason.response.data = transformData(
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
};
// lib/cancel/CancelToken.js
/**
* Throws a `Cancel` if cancellation has been requested.
*/
CancelToken.prototype.throwIfRequested = function throwIfRequested() {
if (this.reason) {
throw this.reason;
}
};