Features
- Make XMLHttpRequests from the browser
- Make http requests from node.js
- Supports the
Promise
API - Intercept request and response
- Transform request and response data
- Cancel requests
- Automatic transforms for JSON data
- Client side support for protecting against XSRF
Config order of precedence
以下优先级依次递增
- axios默认配置,具体在lib/defaults.js
- global axios defaults
axios.defaults.baseURL = 'https://api.example.com';
- Custom instance defaults
const instance = axiso.create({
baseURL: 'https://api.example.com'
});
- request config
instance.get('/users', {
baseURL: 'https://api.github.com'
})
Supports the Promise API
Usage
// Promise
instance.get('/users').then(res => {
console.log(res);
})
// Async | Await
const res = await instance.get('/users');
console.log(res);
Source
// 以 adapter/xhr.js举例
function xhrAdapter (config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
let requestData = config.data;
let request = new XMLHttpRequest();
request.open(config.method.toUpperCase(), URL, true); // 请求尚未发送
request.timeout = config.timeout;
request.onreadystatechange = function handleLoad() {
if (!request || request.readyState !== 4) {
return;
}
const response = {
data,
status: request.status,
statusText: request.statusText,
headers,
config,
request
};
settle(resolve, reject, response);
request = null;
}
if (!requestData) {
requestData = null;
}
// send the request
request.send(requestData);
});
}
// Resolve or reject a Promise based on response status
function settle(resolve, reject, response) {
const validateStatus = response.config.validateStatus;
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(createError('...'));
}
}
Adapter
Usage
const res = await instance.get('/users', {
adapter: function customAdapter(config) {
return fetch(config.url);
}
});
Source
function dispatchRequest (config) {
const adapter = config.adapter || defaults.adapter; // 配置中可以自定义适配器,优先级 自定义适配器 > 默认适配器
return adapter(config).then(function onAdapterResolution(response) {
// ...
}, function onAdapterRejection(reason) {
// ...
})
}
const defaults = {
adapter: getDefaultAdapter()
};
// 根据环境,使用不同适配器
function getDefaultAdapter () {
let adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('./adapter/xhr');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapter/http');
}
return adapter;
}
Transform request and response data
Usage
const res = await instance.get('/user', {
transformRequest: [function (data, headers) {
// Do whatever you want to transform the data
return data;
}],
transformResponse: function (data, headers) {
// Do whatever you want to transform the data
return JSON.parse(data);
}
});
Source
function dispatchRequest(config) {
// Transform request data
config.data = transformData(config.data, config.headers, config.transformRequest); // 自定义请求转换函数
return adapter(config).then(function onAdapterResolution(response) {
// Transform response data
response.data = transformData(response.data, response.headers, config.transformResponse);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason) {
if (reason && reason.response) {
reason.response.data = transformData(reason.response.data, reason.response.headers, config.transformResponse);
}
})
})
}
/*
* @param {Array|Function} fns:A single function or Array of functions to transform data by data and headers
*/
function transformData(data, headers, fns) {
utils.forEach(fns, function transform(fn) {
data = fn(data, headers);
});
return data;
}
Automatic transforms for JSON data
Source
const defaults = {
transformResponse: [function transformResponse(data) {
// 自动进行JSON字符串解析
if (typeof data === 'string') {
data = JSON.parse(data);
}
return data;
}]
};
Interceptors
Usage
// 拦截器注册
// Add a request interceptor
axios.interceptors.request.use(function (config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
Source
// 拦截器收集 [lib/core/InterceptorManager.js](https://github.com/axios/axios/blob/master/lib/core/InterceptorManager.js)
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
// 拦截器触发
Axios.prototype.request = function request(config) {
const chain = [dispatchRequest, undefined];
const 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);
});
// chain = [requestFulfilled, requestRejected, dispatchRequest, undefined, responseFulfilled, responseRejected]
while(chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
// 拦截器顺序:注册 => 收集 => 触发
// 触发顺序:请求拦截器 => 请求 => 响应拦截器
Cancel Requests
Usage
// 发送请求时携带
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
instance.get('/user/12345', {
cancelToken: source.token // 只能叫cancelToken 名字不能改
});
// 取消请求
source.cancel();
Source
function CancelToken(executor) {
let resolvePromise;
this.promise = new Promise(resolve => {
resolvePromise = resolve;
});
const token = this;
executor(function cancel(message) {
if (token.reason) return;
token.reason = new Cancel(message);
resolvePromise(token.reason)
});
}
/**
* Returns an object that contains a new `CancelToken` and a function that, when called,
* cancels the `CancelToken`.
*/
CancelToken.source = function source() {
let cancel; // cancel的值就是上述function cancel方法,执行cancel方法的时候,执行resolvePromise方法
const token = new CancelToken(function executor(c) {
cancel = c;
});
return {
token: token,
cancel: cancel
};
};
// xhr.js 或者 http.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;
});
}
XSRF
XSRF又称CSRF(Cross-site request forgery),是一种劫持受信任用户向服务器发送非预期请求的攻击方式。通常情况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器,从而在并未授权的情况下执行在权限保护之下的操作。一般通过以下三种方式防范:
- 验证码
- Referer Check
- Token
axios库采取了在请求中传入token,防范XSRF攻击。
// axios 默认配置,具体使用时传入自定义xsrfCookieName、xsrfHeaderName
const defaults = {
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN'
};
// add XSRF header
if (utils.isStandardBrowserEnv()) {
const xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ? cookies.read(config.xsrfCookieName) : undefined;
if (xsrfValue) {
requestHeaders[config.xsrfHeaderName] = xsrfValue;
}
}
参考
- 学习 axios:封装一个结构清晰的 Fetch 库
- 浅说 XSS 和 CSRF
- axios README
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!