ToB企服应用市场:ToB评测及商务社交产业平台
标题:
fetch和axios的区别和封装一个功能齐备的axios
[打印本页]
作者:
惊落一身雪
时间:
2024-6-21 13:10
标题:
fetch和axios的区别和封装一个功能齐备的axios
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状态码和贴近业务的一些错误状态)
// http.js
import axios from 'axios';
import { MessageBox, Toast } from 'element-ui'
import qs from qs;
// 环境的切换,也可以写到.env文件中
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, // 允许把cookie传递到后台,
timeout: 1000 * 12
});
http.defaults.timeout = 10000;
// 设置post请求头
http.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
// 请求拦截器
http.interceptors.request.use(
config => {
// 设置 token
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 => { // 服务器状态码不是2开头的的情况
const { response } = error;
if (response) {
// 请求已发出,但是不在2xx的范围
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) {
// 401: 未登录状态,跳转登录页
case 401:
toLogin();
break;
// 403 token过期
// 清除token并跳转登录页
case 403:
Toast('登录过期,请重新登录');
localStorage.removeItem('token');
store.commit('loginSuccess', null);
setTimeout(() => {
toLogin();
}, 1000);
break;
// 404请求不存在
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;
复制代码
// api.js
import request from "./http.js";
// 文件下载
export const exportFile = (data) =>
request.post("/exportfile", data, {
responseType: "blob",
});
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4