axios和fetch区别
- 概念不同
- Fetch是一种新的获取资源的接口方式,可以直接使用
- Axios是一个基于XMLHttpRequest封装的工具包,需要引入才可以使用
- 传递数据的方式不同
- Fetch则是需要放在body属性中,以字符串的方式进行传递
- Axios是放到data属性里,以对象的方式进行传递
- 响应超时
- Fetch需要通过AbortController来设置
- Axios是直接设置timeout就可以
- 对数据的转化
- Fetch则不同,它需要使用者进行手动转化,arrayBuffer(),blob(),json(),text(),formData()
- Axios还有非常好的一点就是会自动对数据进行转化
- HTTP拦截器
- Fetch没有拦截器功能,但是要实现该功能并不难,直接重写全局Fetch方法就可以办到
- Axios设置拦截器非常简单,通过axios.interceptors.request.use(() => {})
封装axios
- 优化配置,设置默认配置项(responseType、跨域携带cookie、token、超时设置),统一设置请求头、 baseURL
- 添加请求拦截器、响应拦截器
- 不同请求方法,参数格式一致
- 全局的loading配置
- 支持下载文件
- 取消重复请求(取消请求详解)
- 可进行二次确认(一般删除、重置等方法防止用户误触会进行二次确认)
- 统一处理错误,http状态码和贴近业务的一些错误状态)
import axios from 'axios';
import { MessageBox, Toast } from 'element-ui'
import qs from qs;
if (process.env.NODE_ENV == 'development') {
axios.defaults.baseURL = 'https://www.baidu.com';}
else if (process.env.NODE_ENV == 'debug') {
axios.defaults.baseURL = 'https://www.ceshi.com';
}
else if (process.env.NODE_ENV == 'production') {
axios.defaults.baseURL = 'https://www.production.com';
}
let http = axios.create({
withCredentials: true,
timeout: 1000 * 12
});
http.defaults.timeout = 10000;
http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
http.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
token && (config.headers.Authorization = token)
addPendingRequest(config)
return config;
},
error => {
return Promise.reject(error);
}
);
http.interceptors.response.use(
response => {
removePendingRequest(response.config);
if (response.data instanceof Blob) {
return downloadFile(response);
}
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
error => {
const { response } = error;
if (response) {
errorHandle(response.status, response.data.message);
return Promise.reject(response);
} else {
if (!window.navigator.onLine) {
return Promise.reject(new Error('请检查网络连接'))
} else {
return Promise.reject(error);
}
}
}
);
const errorHandle = (status, other) => {
switch (status) {
case 401:
toLogin();
break;
case 403:
Toast('登录过期,请重新登录');
localStorage.removeItem('token');
store.commit('loginSuccess', null);
setTimeout(() => {
toLogin();
}, 1000);
break;
case 404:
Toast('请求的资源不存在');
break;
default:
console.log(other);
}
}
export const post = (url, params, confirm = false) => {
return new Promise((resolve, reject) => {
if (confirm || confirm.confirm) {
MessageBox.confirm(confirm.confirm || '确认操作吗', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
resolve(http.post(url, params))
})
.catch(_ => {
console.log('取消请求')
})
} else {
resolve(http.post(url, params))
}
})
}
let repeatRequests = {}
function generateRequestKey(config) {
const { method, url, params, data } = config
const split = '---'
const array = [`url:`, url, `${split}method:`, method]
params && array.push(`${split}params:`, qs.stringify(params))
data && array.push(`${split}data:`, typeof data === 'object' ? JSON.stringify(data) : data)
return array.join('')
}
function addPendingRequest(config) {
const requestKey = generateRequestKey(config)
config.cancelToken = new axios.CancelToken(cancel => {
!repeatRequests[requestKey] && (repeatRequests[requestKey] = [])
repeatRequests[requestKey].push(cancel)
})
return config
}
function removePendingRequest(config) {
const requestKey = generateRequestKey(config)
const needCancel = repeatRequests[requestKey]?.length > 1
if (needCancel) {
repeatRequests[requestKey].forEach(cancel => {
cancel(requestKey)
})
}
needCancel ? (repeatRequests[requestKey] = []) : (repeatRequests = {})
}
const downloadFile = (response) => {
console.log("response.data.type:", response.data.type);
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.onload = function () {
try {
console.log("result:", this.result);
const jsonData = JSON.parse(this.result);
if (jsonData?.code !== 200) {
Message.error(jsonData?.message ?? "请求失败");
reject(jsonData);
}
} catch (err) {
const blob = new Blob([response.data]);
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
const filename = response?.headers?.["content-disposition"]
?.split("filename*=")?.[1]
?.substr(7);
link.setAttribute("download", decodeURI(filename));
document.body.appendChild(link);
link.click();
resolve(response.data);
}
};
fileReader.readAsText(response.data);
});
};
export default http;
import request from "./http.js";
export const exportFile = (data) =>
request.post("/exportfile", data, {
responseType: "blob",
});