前言
Axios 是一个基于 promise 的 HTTP 库,用于各种接口请求数据,可以用在浏览器和 node.js 中。
Axios 优势
- 支持 Promise
- 客户端支持防止 CSRF
- 丰富的接口 API(并发请求等)
- 请求/响应拦截器
- 转换请求和响应数据(自动转换 JSON 数据等)
- 取消阻止请求
安装
1
| $ npm install axios --save
|
例子
执行 GET
请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| axios .get('http://api.example.com/user?ID=12345') .then((res) => { console.log(res) }) .catch((error) => { console.log(error) })
axios .get('http://api.example.com/user', { params: { ID: 12345 } }) .then() .catch()
|
执行 POST
请求:
1 2 3 4 5 6 7 8 9 10 11 12 13
| axios .post('http://api.example.com/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then((res) => { console.log(response) }) .catch((error) => { console.log(error) })
|
Axios API
Axios 请求
可以通过 axios
传递配置参数来创建请求:
axios(config)
1 2 3 4 5 6 7 8 9
| axios({ method: 'post', url: '/user/12345', data: { firstName: 'Fred', lastName: 'Flintstone' } })
|
axios(url[, config])
请求方法
Axios 为所有支持的请求方法提供了别名。
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
这些属性不必在 config
配置中指定。
并发请求
Axios 处理并发请求的两个助手函数:
axios.all([])
: 用于发送并发请求;
axios.spread(callback)
: 用于请求数据回调;
1 2 3 4 5 6 7 8 9 10 11
| axios.all([axios('api/account'), axios('api/config')]) .then(axios.spread(function (res1, res2) { }));
axios.all([axios('api/account'), axios('api/config')]) .then(res => { console.log(res[0]); console.log(res[1]); }));
|
config 配置
创建请求时可以指定配置选项,其中只有 url
时必需的。
常见的配置有:
url
: 指定请求服务器地址;
method
: 指定请求方法;
baseURL
: 指定请求基础地址,会自动加在 url 前面,除非 url 是一个绝对地址;
headers
: 指定请求头;
params
: 指定 URL 中的 params 参数;
data
: 指定发送数据,只适用于POST
、PUT
、PATCH
方法;
timeout
: 指定请求超时时间,单位毫秒;
responseType
: 指定响应数据类型,默认 json;
proxy
: 指定代理服务器;
以下为所有可以使用的配置选项:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| { url: '/user',
method: 'get',
baseURL: 'https://some-domain.com/api/',
transformRequest: [function (data) {
return data; }],
transformResponse: [function (res) {
return res; }],
headers: {'X-Requested-With': 'XMLHttpRequest'},
params: { ID: 12345 },
paramsSerializer: function(params) { return Qs.stringify(params, {arrayFormat: 'brackets'}) },
data: { firstName: 'Fred' },
timeout: 1000,
withCredentials: false,
adapter: function (config) { },
auth: { username: 'janedoe', password: 's00pers3cret' },
responseType: 'json',
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
onUploadProgress: function (progressEvent) { },
onDownloadProgress: function (progressEvent) { },
maxContentLength: 2000,
validateStatus: function (status) { return status >= 200 && status < 300; },
maxRedirects: 5,
httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }),
proxy: { host: '127.0.0.1', port: 9000, auth: : { username: 'mikeymike', password: 'rapunz3l' } },
cancelToken: new CancelToken(function (cancel) { }) }
|
响应结构
Axios 请求响应包含以下信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| { data: {},
status: 200,
statusText: 'OK',
headers: {},
config: {} }
|
请求成功以上响应信息会出现在 response 对象中:
1 2 3 4 5 6 7
| axios.get('/user/1111').then((res) => { console.log(res.data) console.log(res.status) console.log(res.statusText) console.log(res.headers) console.log(res.config) })
|
请求失败时,响应信息会出现在 error.response
对象中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| axios.get('/user/12345').catch(function (error) { if (error.response) { console.log(error.response.data) console.log(error.response.status) console.log(error.response.headers) } else if (error.request) { console.log(error.request) } else { console.log('Error', error.message) } console.log(error.config) })
|
Axios 实例
一般使用中,项目可能不只包含一个 API 接口,每个接口可能有不同的默认配置对象,也有可能需要为每个接口设置不同的拦截器,所以并不会直接使用 axios
对象来发送请求,而是创建一个 Axios 实例来对接口做一个封装,再通过实例来发送请求。
axios.create(config)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const instance = axios.create({ baseURL: 'https://some-domain.com/api/', timeout: 1000, headers: { 'X-Custom-Header': 'foobar' } })
instance({ url: '/user', params: { id: 12345 } })
instance.get('/user?id=12345')
|
默认配置
可以指定请求时的默认配置,避免每次请求来重复配置。
通过 axios.defaults
修改全局默认配置:
1 2 3
| 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 2 3 4 5 6 7 8
| const instance = axios.create({ baseURL: 'https://api.example.com', timeout: 5000 })
instance.defaults.timeout = 2500
|
默认配置的优先级遵循向上查找:
发送请求时配置 > 实例默认配置 > 全局默认配置
拦截器
拦截器是在发送请求或得到响应处理前拦截,从而对数据进一步操作再发送请求或响应,及在被 then
或 catch
前拦截。
使用场景:
- 对请求统一做错误处理;
- token 处理(是否携带 token 等);
axios.interceptors.request.use()
: 请求拦截器;
axios.interceptors.respones.use()
: 响应拦截器;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| axios.interceptors.request.use( (config) => {
return config }, (error) => {
return Promise.reject(error) } )
axios.interceptors.response.use( (res) => {
return res }, (error) => { return Promise.reject(error) } )
|
同样,一般不会在 axios 中添加全局拦截器,而是在实例中添加拦截器:
1 2 3 4
| const instance = axios.create() instance.interceptors.request.use(function () { })
|
移除拦截器:
1 2 3 4
| const myInterceptor = axios.interceptors.request.use(function () { }) axios.interceptors.request.eject(myInterceptor)
|
默认情况下,axios
将数据对象序列化为JSON
来发送请求,某些接口可能需要使用 application/x-www-form-urlencoded
格式发送数据,首先需要指定请求头的 content-type
,再者需要将数据序列化为对应格式。
可利用第三方库 qs 来序列化数据,而且 qs 库在很多依赖包中都有使用到,不用重新下载依赖,直接引入使用。
node 中可使用 querystring 模块,用法与 qs 基本相同。
1 2 3 4 5 6 7 8 9 10
| import axios from 'axios'; import qs from 'qs';
const data = { id: '888', name: 'Vincent' }; axios({ url: 'https://api.example.com/user' method: 'POST', headers: { 'content-type': 'application/x-www-form-urlencoded' }, data: qs.stringify(data) });
|
关于 qs 库,这里列举序列化和解析,其它方法详情可戳这里。
1 2 3 4 5 6 7
| const data = { id: '888', name: 'Vincent' } qs.stringify(data)
const str = 'firstName=Vincent&lastName=F0ng' qs.parse(url)
|
封装
创建 axiose 实例及默认配置:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| import axios from 'axios'
export function request(config) { const instance = axios.create({ baseURL: 'http://api.example.com', timeout: 5000 })
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
instance.interceptors.request.use( (config) => { return config }, (err) => { return Promise.reject(error) } )
instance.interceptors.response.use( (res) => { return res.data }, (err) => { return Promise.reject(err) } )
return instance }
|
封装接口请求函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| import { request } from './request'
export function getMultidata() { return request({ url: '/home/multidata' }) }
export function getList(type, page) { return request({ url: '/home/data', params: { type, page } }) }
|
接口调用:
1 2 3 4 5 6 7 8 9 10 11
| import { getMultidata, getList } from '@/api/api.js'
getMultidata() .then((res) => { }) .catch((err) => { })
getList().then((res) => {})
|
封装的意义:在使用第三方库时,可能面临更换库的时候,如果每个请求都调用 aixos
,更换库时所有使用到 aixos
的地方都需要修改。而如上封装,返回的是 promise
对象,即使更换库也只需要修改 @/api/request.js
文件,确保返回的同样是一个 promise
对象即可。