小工具知识网

当前位置: 首页 > 行业知识 > fetch和axios的区别和封装一个功能齐全的axios

行业知识

fetch和axios的区别和封装一个功能齐全的axios

2026-11-10 17:45:52 来源:互联网转载

axios和fetch区别

  1. 概念不同
    • 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.jsimport 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.jsimport request from "./http.js";// 文件下载export const exportFile = (data) =>  request.post("/exportfile", data, {    responseType: "blob",  });

上一篇:宝塔面板怎么重新装?

下一篇:揭秘日历备注消失原因,解决你的日程管理难题!