一.axios是什么
概述:
Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http
模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
axios有以下特性:
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
历史:
在旧浏览器页面在向服务器请求数据时,因为返回的是整个页面的数据,页面都会强制刷新一下,这对于用户来讲并不是很友好。我们只是需要修改页面的部分数据,也希望不刷新页面,但是从服务器端发送的却是整个页面的数据,十分消耗网络资源,因此异步网络请求(Ajax)就应运而生。
Ajax(Asynchronous JavaScript and XML):
异步网络请求。Ajax能够让页面无刷新的请求数据。
实现ajax的方式有多种,如jQuery封装的ajax,原生的XMLHttpRequest,以及axios。但各种方式都有利弊:
- 原生的XMLHttpRequest的配置和调用方式都很繁琐,实现异步请求十分麻烦
- jQuery的ajax相对于原生的ajax是非常好用的,但是jQuery框架比较‘重’,没有必要因为要用ajax异步网络请求而引用jQuery框架
- Axios(ajax i/o system):这不是一种新技术,本质上还是对原生XMLHttpRequest的封装,可用于浏览器和nodejs的HTTP客户端,只不过它是基于Promise的,符合最新的ES规范。
想要知道更多关于Ajax的内容请看我的这篇文章,戳我传送,本篇文章主要讲解axios,Ajax在这里就不过多介绍了
二.axios介绍
axios是基于Promise的,因此可以使用Promise API
1.axios可以请求的方法:
- get:获取数据,请求指定的信息,返回实体对象
- post:向指定资源提交数据(例如表单提交或文件上传)
- put:更新数据,从客户端向服务器传送的数据取代指定的文档的内容
- patch:更新数据,是对put方法的补充,用来对已知资源进行局部更新
- delete:请求服务器删除指定的数据
- head:获取报文首部
2.请求方法别名
为了方便起见,axios为所有支持的请求方法提供了别名:
- axios(config)
- axios.request(config)
- axios.get(url [,config])
- axios.post(url [,data [,config]])
- axios.put(url [,data [,config]])
- axios.delete(url [,config])
- axios.patch(url [,data [,config]])
- axios.head(url [,config])
get、post请求代码示例:
//执行GET请求
import axios from 'axios'
axios.default.baseURL = 'http://localhost:3000/api/products'
axios.get('/user?ID=12345') //返回的是一个Promise
.then(res=>console.log(res))
.catch(err=>console.log(err));
//可配置参数的方式
axios.get('/user',{
params:{
ID:12345
}
}).then(res=>console.log(res))
.catch(err=>console.log(err));
//发送post请求
axios.post('/user',{
firstName: 'ziming',
lastName:'song'
}).then(res=>console.log(res))
.catch(err=>console.log(err));
3.并发请求
通过axios.all(iterable)可实现发送多个请求,参数不一定是数组,只要有iterable接口就行,函数返回的是一个数组
axios.spread(callback)可用于将结果数组展开
axios.all([
axios.get('/goods.json'),
axios.get('/class.json')
]).then(axios.spread((goodsRes,classRes)=>{
console.log(goodsRes.data);
console.log(classRes.data);
}))
三.axios API
1.向 axios 传递相关配置来创建请求
代码示例:
1.axios(config)
// 发送 POST 请求
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'song',
lastName: 'ziming'
}
});
2.axios(url[, config])
// 默认发送 GET 请求
axios('/user/12345');
2.用axios提供的请求方法发送请求
代码示例:
1.axios.get(url[, config]) 执行 GET 请求
// 向具有指定ID的用户发出请求
axios.get('/user?ID=12345')
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
// 也可以通过 params 对象传递参数
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
2.axios.post(url[, data[, config]]) 执行 POST 请求
axios.post('/user', {
firstName: 'song',
lastName: 'ziming'
})
.then(function (res) {
console.log(res);
})
.catch(function (err) {
console.log(err);
});
3.axios.request(config)//用法同上
4.axios.head(url[, config])//用法同上
5.axios.delete(url[, config])//用法同上
6.axios.put(url[, data[, config]])//用法同上
7.axios.patch(url[, data[, config]])//用法同上
8.axios.all(iterable)执行多个并发请求
9.axios.spread(callback)展开
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
四.axios实例及配置方法
1.创建axios实例
axios.create([config])
可以同时创建多个axios实例。
代码示例:
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
实例方法
以下是可用的实例方法。指定的配置将与实例的配置合并。
- 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]])
- axios#getUri([config])
2.配置方法
配置对象常用的配置项:
这些是创建请求时可以用的配置选项。只有 url
是必需的。如果没有指定 method
,请求将默认使用 GET
方法。更多配置项请查看官方文档,戳我传送
{
// 路径url
url: '/user',
// 请求方法,默认get
method: 'get',
//基础url,最终请求的url是 baseURL+url拼接,所以再全局设置默认,可以使得发送请求时的url变得简洁
baseURL: 'https://some-domain.com/api/',
//设置请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
//设置请求url的query参数,可以使得url简洁。
//比如url是https://some-domain.com/api/user 然后params如下设置,那么最终的url是:
//https://some-domain.com/api/user?ID=12345&name=Jack
params: {
ID: 12345,
name:"Jack"
},
//设置请求体
data: {
firstName: 'Fred'
},
//设置请求的另外一种格式,不过这个是直接设置字符串的
data: 'Country=Brasil&City=Belo Horizonte',
//请求超时,单位毫秒,默认0,不超时。
timeout: 1000,
//响应数据类型,默认json
responseType: 'json',
//响应数据的编码规则,默认utf-8
responseEncoding: 'utf8',
//响应体的最大长度
maxContentLength: 2000,
// 请求体的最大长度
maxBodyLength: 2000,
//设置响应状态码为多少时是成功,调用resolve,否则调用reject失败
//默认是大于等于200,小于300
validateStatus: function (status) {
return status >= 200 && status < 300;
},
默认配置
可以设置全局默认配置,是为了避免多种重复配置在不同请求中重复,比如baseURL、timeout等,这里设置baseURL。
全局 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';
自定义实例默认值
// 创建实例时配置默认值
const instance = axios.create({
baseURL: 'https://api.example.com'
});
// 创建实例后修改默认值
instance.defaults.headers.common['Authorization'] = AUTH_TOKEN;
配置的优先级
配置将会按优先级进行合并。它的顺序是:在 lib/defaults.js 中找到的库默认值,然后是实例的 defaults
属性,最后是请求的 config
参数。后面的优先级要高于前面的。
五.拦截器
在请求或响应被 then 或 catch 处理前拦截它们,自定义的axios实例也可添加拦截器,如:
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
请求拦截器
示例代码:
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
响应拦截器
示例代码:
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
取消拦截器
示例代码:
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
六.取消请求
注意:从 v0.22.0
开始,Axios 支持以 fetch API 方式—— AbortController 取消请求,CancelToken API被弃用
这里我们两种方法都介绍一下,使用过程中能用 AbortController 就尽量别用 CancelToken
AbortController
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) {
//...
});
// 取消请求
controller.abort()
CancelToken
let source = axios.CancelToken.source();
axios.get('/users/12345',{
cancelToken: source.token
}).then(res=>{
console.log(res)
}).catch(err=>{
//取消请求后会执行该方法
console.log(err)
})
//取消请求,参数可选,该参数信息会发送到请求的catch中
source.cancel('取消后的信息');
也可以通过传递一个 executor 函数到 CancelToken
的构造函数来创建一个 cancel token:
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();
注意: 可以使用同一个 cancel token 或 signal 取消多个请求
axios封装
先设计我们想要这个通用请求能达到什么样的效果:
- 优化配置,设置默认配置项(responseType、跨域携带cookie、token、超时设置)
- 统一设置请求头
- 根据环境设置 baseURL
- 通过 Axios 方法直接发起请求
- 添加请求拦截器
- 添加响应拦截器
- 导出
Promise
对象 - 封装 Post 方法,精简 post 请求方式
- 封装 Get 方法,精简 get 请求方式
- 请求成功,配置业务状态码
- 全局的loading配置
我们需要根据不同的需求进行不同程度的封装,这里介绍一下封装方法,就不一一进行二次封装实现
// src/api/axios.js
import axios from "axios";
import Qs from 'qs'
import store from '@/store'
import { getToken } from '@/utils/auth'
export const Axios = (url,method='get',params={},headers={})=>{
// 根据定义的环境状态,切换不同的 baseURL 开发环境使用代理, 生产环境可以直接使用域名全拼
const BaseUrl = process.env.NODE_ENV==='development'? '' : process.env.BASEURL;
let defaultHeaders = {
'Content-Type': 'application/json;charset=UTF-8',
// 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', // 指定提交方式为表单提交 或上传
// 'Content-Type' :'multipart/form-data;charset=UTF-8',
'Accept': 'application/json', // 通过头指定,获取的数据类型是JSON
// 'Access-Control-Allow-Origin': 'true',
// 'Access-Control-Allow-Credentials': 'true',
}
if(headers){
for (let i in headers) {
defaultHeaders[i] = headers[i];
}
}
//在响应拦截中,如果有需要还可以对状态码提示进行处理。现在项目一般后端都会给处理好,
//这个根据自己的项目情况进行配置,这里只做部分常见的示例
const showResState = (state) => {
let message = ''
switch (state) {
case 400:
message = '请求错误(400)'
break
case 401:
message = '未授权,请重新登录(401)'
break
case 403:
message = '拒绝访问(403)'
break
case 404:
message = '请求出错(404)'
break
case 500:
message = '服务器错误(500)'
break
case 501:
message = '服务未实现(501)'
break
case 502:
message = '网络错误(502)'
break
case 503:
message = '服务不可用(503)'
break
default:
message = `连接出错(${state})!`
}
return `${message},请检查网络或联系网站管理员!`
}
// 添加请求拦截器
axios.interceptors.request.use( config => {
// 在发送请求之前做些什么
// header 配置 Token 判断Token是否过期 没过期则正常处理 过期则发起刷新Token的请求拿到新的Token保存
config.headers.Authorization = null;
// if (store.getters.token) {
// config.headers['token'] = getToken()
//}
//else{
// alert("Token已失效")
// }
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use((res) => {
// 对响应数据做点什么
const status = res.status;
let msg = ''
if (status < 200 || status >= 300) {
// 处理http错误,抛到业务代码
msg = showResState(status)
if (typeof res.data === 'string') {
res.data = { msg }
} else {
res.data.msg = msg
}
}
return res;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
// 1. 执行异步ajax请求
const instance = axios({
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: BaseUrl,
// `url` 是用于请求的服务器
url: url,
// `method` 是创建请求时使用的方法
method: method || 'get',
// mode: 'cors',
// cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
// `headers` 是即将被发送的自定义请求头
headers: {...defaultHeaders},
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data, headers) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: method === 'get' ? params || {} : {},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: method === 'post' ? params || {} : {},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求话费了超过 `timeout` 的时间,请求将被中断
timeout: 0,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // default 为true则产生跨域,跨域携带cookie
// `responseType` 表示服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // default
});
return new Promise((resolve, reject) => {
instance.then(response => {
// 2. 如果成功了, 调用resolve(value)
resolve(response);
})
.catch(error => {
// 3. 如果失败了, 不调用reject(reason), 而是提示异常信息
reject(error)
}).finally(() => {
})
});
}
// GET 请求 get 下 params 为查询参数
export const Get = (url,params={},headers={}) => {
return Axios(url,'get',params,headers)
}
// POST 请求 post 下 params 为body参数, 如果 post 下既需要传查询参数也需要传实体参数,则查询参数配置在 url 中
export const Post = (url,params={},headers={}) => {
return Axios(url,'post',params,headers)
}