1、axios简介
axios:基于promise可以用于浏览器和node.js的网络请求库
特性
- 在服务器端,基于node的http模块
- 在浏览器端,使用XMLHttpRequests实现;
- 使用Promise API
- 拦截请求和响应
- 对请求和响应数据进行转换
- 可以取消请求
- 自动转换成json数据格式
- 客户端支持防护XSRF安全攻击
安装
//npm
npm install axios
//yarn
yarn add axios
//CDN
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
2、axios使用
简单使用说明
- Get请求
const axios = require('axios');
// 向给定ID的用户发起请求
axios.get('/user?ID=12345')
.then(function (response) {
// 处理成功情况
console.log(response);
})
.catch(function (error) {
// 处理错误情况
console.log(error);
})
// request中的querystring被param代替
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
// 支持async/await + try-catch固定写法
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
- Post请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
- 处理多个请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
//使用promise.all方法
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});
//使用async、await
aysnc function getAcountAndPerm(){
try{
const acct = await getUserAccount();
const perm = await getUserPermissions();
}catch(err){
console.log(err)
}
}
axios API文档
//当做函数使用,相当于axios.request
axios(config)
axios(url[,config])
//当做对象使用,使用原型方法
//将url从config中提出来,config是可选的
axios.request(config)
axios.get(url[,config])
axios.delete(url[,config])
axios.head(url[,config])
axios.option(url[,config])
//可以将url和data从config中提出来,config是可选的
axios.post(url[,data[,config]])
axios.put(url[,data[,config]])
axios.patch(url[,data[,config]])
//创建axios实例对象,instance和axios默认api一致,可以有一些个性化的参数配置,同时少一些axios属性。
const instance = axios.create([config])
axios 请求配置
//config对象内容
{
// `url`请求路径
url: '/user',
// `method` 请求方法,默认是get
method: 'get',
// `baseURL` url前缀
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 请求数据转换
transformRequest: [function (data, headers) {
return data;
}],
// `transformResponse` 响应数据转换
transformResponse: [function (data) {
return data;
}],
// `headers` 请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 请求参数
params: {
ID: 12345
},
// `paramsSerializer` 参数序列化方式
paramsSerializer: function (params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 请求数据
data: {
firstName: 'Fred'
},
// `timeout` 请求超时时间 毫秒
timeout: 1000,
// `withCredentials` 是否允许跨域
withCredentials: false,
// `adapter` 请求适配器,自定义实践用于测试
adapter: function (config) {
/* ... */
},
// `auth` 请求认证信息
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 返回数据类型
responseType: 'json',
// `responseEncoding` 返回数据编码
responseEncoding: 'utf8',
// `xsrfCookieName` xsrf token
xsrfCookieName: 'XSRF-TOKEN',
// `xsrfHeaderName` xsrf token value
xsrfHeaderName: 'X-XSRF-TOKEN',
// `onUploadProgress` 上传事件处理钩子
onUploadProgress: function (progressEvent) {
},
// `onDownloadProgress` 下载事件处理钩子
onDownloadProgress: function (progressEvent) {
},
// `maxContentLength` node最大处理长度
maxContentLength: 2000,
// `maxBodyLength` (Node only option)
maxBodyLength: 2000,
// `validateStatus` 成功状态判定
validateStatus: function (status) {
return status >= 200 && status < 300;
},
// `maxRedirects` 最大转发次数
maxRedirects: 21,
// `beforeRedirect`
beforeRedirect: (options, { headers }) => {
if (options.hostname === "example.com") {
options.auth = "user:password";
}
};
// `socketPath` defines a UNIX Socket to be used in node.js.
socketPath: null, // default
// `httpAgent` and `httpsAgent` define a custom agent to be used when performing http
// and https requests, respectively, in node.js. This allows options to be added like
// `keepAlive` that are not enabled by default.
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy` defines the hostname, port, and protocol of the proxy server.
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` 定义取消请求对象
cancelToken: new CancelToken(function (cancel) {
}),
// 另一种取消请求方式
signal: new AbortController().signal,
// - Node only (XHR cannot turn off decompression)
decompress: true // default
// `insecureHTTPParser` boolean.
insecureHTTPParser: undefined
env: {
FormData: window?.FormData || global?.FormData
}
}
axios响应对象
{
// `data` 服务端返回数据
data: {},
// `status` HTTP响应码
status: 200,
// `statusText` HTTP响应文本
statusText: 'OK',
// `headers` http响应头
headers: {},
// `config` 请求的request config对象
config: {},
// `request` 请求体
request: {}
}
拦截器
// 增加一个请求拦截器 req1
axios.interceptors.request.use(function req1(config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// 增加一个请求拦截器 req2
axios.interceptors.request.use(function req2(config) {
// Do something before request is sent
return config;
}, function (error) {
// Do something with request error
return Promise.reject(error);
});
// 增加一个响应拦截器 res1
axios.interceptors.response.use(function res1(response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
// 增加一个响应拦截器res2
axios.interceptors.response.use(function res1(response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
return Promise.reject(error);
});
- request 拦截器传递修改的是config请求配置对象
- response拦截器传递修改的是response返回体对象
- 按照执行器的实现逻辑,请求拦截器会在对头插入,响应拦截器会在队尾插入。因此上述代码执行顺序是:req2-->req1-->dispatch-->res1-->res2
取消请求
- CancelToken(不推荐使用了)
const CancelToken = axios.CancelToken;
let cancel;
//请求时config中配置cancelToken
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
cancel = c;
})
});
// 取消请求,用户需要时
cancel();
- AbortController
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
3、axios核心源码
文件目录
|-- lib
|-- axios.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
|-- defaults
| |-- index.js
| |-- transitional.js
|-- env
| |-- data.js
| |-- README.md
|-- 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
|-- toFormData.js
|-- validator.js
core/Axios.js
//构造函数,并增加defauts和interceptors两个实例对象属性
function Axios(instanceConfig) {
this.defaults = instanceConfig;
//拦截器熟悉包含request,和response两个对象,值为InterceptorManager对象
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
- request函数
//Axios原型方法上,最核心的request函数
Axios.prototype.request = function request(configOrUrl, config) {
if (typeof configOrUrl === 'string') {
config = config || {};
config.url = configOrUrl;
} else {
config = configOrUrl || {};
}
config = mergeConfig(this.defaults, config);
// Set config.method
if (config.method) {
config.method = config.method.toLowerCase();
} else if (this.defaults.method) {
config.method = this.defaults.method.toLowerCase();
} else {
config.method = 'get';
}
var transitional = config.transitional;
if (transitional !== undefined) {
validator.assertOptions(transitional, {
silentJSONParsing: validators.transitional(validators.boolean),
forcedJSONParsing: validators.transitional(validators.boolean),
clarifyTimeoutError: validators.transitional(validators.boolean)
}, false);
}
// 添加实例请求拦截器,unshift到队头
var requestInterceptorChain = [];
var synchronousRequestInterceptors = true;
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
return;
}
synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
});
//添加响应拦截器,push到队尾
var responseInterceptorChain = [];
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
});
var promise;
if (!synchronousRequestInterceptors) {
//实际请求处理,reject为undefined起到一个占位作用
var chain = [dispatchRequest, undefined];
Array.prototype.unshift.apply(chain, requestInterceptorChain);
chain = chain.concat(responseInterceptorChain);
promise = Promise.resolve(config);
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
var newConfig = config;
//请求拦截器执行,onFullfilled有用户config传入,并修改config
while (requestInterceptorChain.length) {
var onFulfilled = requestInterceptorChain.shift();
var onRejected = requestInterceptorChain.shift();
try {
newConfig = onFulfilled(newConfig);
} catch (error) {
onRejected(error);
break;
}
}
//执行dispatchRequest-->adapter方法完成实际请求,返回一个promise
try {
promise = dispatchRequest(newConfig);
} catch (error) {
return Promise.reject(error);
}
//通过then方法执行响应拦截器,处理response对象
while (responseInterceptorChain.length) {
promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
}
return promise;
};
// 定义delete、get、head、options方法,使用request实现
utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
//在Axios原型对象上加上这些熟悉方法
Axios.prototype[method] = function(url, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: (config || {}).data
}));
};
});
// 定义post、put、patch方法,使用request实现,比上面多了data属性
utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
/*eslint func-names:0*/
Axios.prototype[method] = function(url, data, config) {
return this.request(mergeConfig(config || {}, {
method: method,
url: url,
data: data
}));
};
});
core/InterceptorManager
拦截器相关对象
//函数对象,包含一个拦截器数组
function InterceptorManager() {
this.handlers = [];
}
//函数对象原型上增加use方法,实际是往handlers对象中添加成功和失败回调函数
InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected,
synchronous: options ? options.synchronous : false,
runWhen: options ? options.runWhen : null
});
return this.handlers.length - 1;
};
core/dispatchRequest.js
dispatchRequest将请求转发到相应的adapter上,完成请求的发送和处理。
module.exports = function dispatchRequest(config) {
//忽略了一些异常处理和headers相关代码
//查看request config中是否配置了适配器,如果没有从defaults中获取
//后面分析
var adapter = config.adapter || defaults.adapter;
/***
//以下代码在defaults/index.js中可以看出,默认的adapter是根据如下规则进行判断
//如果有XMLHttpRequest,则为浏览器端,使用xhrAdapter
//如果有process对象,则为node端,使用httpAdapter
function getDefaultAdapter() {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('../adapters/xhr');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('../adapters/http');
}
return adapter;
}
**/
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData.call(
config,
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.call(
config,
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
};
adapters
| 名称 | 作用 |
|---|---|
| adapters/xhr.js | 基于ajax封装浏览器端实际请求的实现 |
| adapters/http.js | 基于http/https实现node端网络请求 |