axios封装以及详细用法axios请求拦截响应拦截请求重试请求终止 fetch请求

33 篇文章 0 订阅
21 篇文章 0 订阅

axios官方文档

说明:这里是在老项目中继续封装的,如果新项目可以将index.ts中的响应拦截异常处理和request中的异常处理合并在一起,无感刷新token,由于提供了思路,以供参考

index.ts(基础封装)

axios的基本封装(请求拦截、响应拦截)

import { message } from 'ant-design-vue';
import axios from 'axios';
import router from '../router';
import { globalData } from '../setting/global';
import { ref } from 'vue';
const host = ref('localhost');
const serverUrl = ref('localhost');

//这里是electron中的本地存储,如果不知道可以理解为localstory
const Store = require('electron-store');

const store = new Store();

const serverAddressIp = store.get('serverAddressIp'); //是否首次输入服务器IP
if (serverAddressIp) {
  host.value = serverAddressIp;
}

serverUrl.value = 'http://' + host.value + ':8102';

//用于更新用户切换链接的服务器IP
export function updateServer(address: string) {
  host.value = address;
  serverUrl.value = 'http://' + host.value + ':8102';
}

export const serverAddress = () => serverUrl.value + '/';

export const serverIp = () => host.value;

axios.defaults.withCredentials = true;

let config = {
  baseURL: serverUrl.value ? serverUrl.value : globalData.apiUrl,
  withCredentials: true,
  Headers: {
    'Content-Type': 'application/json',
  },
  timeout: 10 * 60 * 1000,
};

const http = axios.create(config);

http.interceptors.request.use(
  (config: any) => {
    const token = sessionStorage.getItem('TOKEN');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    config.headers['Content-Type'] = 'application/json';
    config.url = serverUrl.value + config.url;
    return config;
  },
  (error) => {
    // Do something with request error
    return Promise.reject(error);
  },
);

// Add a response interceptor
http.interceptors.response.use(
  (response) => {
    // Do something with response data
    return response.data;
  },
  (error) => {
    if (error.message.includes('timeout')) {
      return Promise.reject('timeout');
      message.error('任务执行时间过长');
    } else if (error.response?.status === 401) {
      message.error('身份已失效,请重新登录!');
      router.push('/login');
    } else if (error.response?.status === 405) {
      message.error('请求方式错误');
    } else if (error.response?.status === 500) {
      message.error('服务器内部错误');
    } else if (error.response?.status === 400) {
      //下面就不改了,项目中改动太多
      console.log('请求错误');
    } else if (error.response?.status === 403) {
      console.log('拒绝访问');
    } else if (error.response?.status === 404) {
      console.log('请求地址出错');
    } else if (error.response?.status === 422) {
      console.log('请求参数错误');
    } else if (error.response?.status === 501) {
      console.log('服务未实现');
    } else if (error.response?.status === 502) {
      console.log('网关错误');
    } else if (error.response?.status === 503) {
      console.log('服务不可用');
    } else if (error.response?.status === 504) {
      console.log('网关超时');
    } else if (error.response?.status === 505) {
      console.log('HTTP版本不受支持');
    }
    // Do something with response error
    return Promise.reject(error.response);
  },
);

export default http;

request.ts

在index.ts的基础上增加请求重试、请求终止(也可以实现无感刷新)

import http from './index';

const timeout = 60000; // 超时时间 官方默认3000      index.ts 设置了600000ms

let configTemp: any = {};
// 执行请求的方法
function request(config: any, retryTime: number) {
  configTemp = config;

  return http({
    ...config,
    // timeout,
  })
    .then((res) => {
      return Promise.resolve(res);
    })
    .catch((error) => {
      // 先解释一下,由于这里是在老项目中封装的,为了兼容之前写的项目不做调整,就在这里异常处理,其实index.ts中的catch完全可以放在这里处理
      console.log(error);
      if (error.includes('timeout'))
        if (retryTime >= 3) {
          // 重试次数超过了限制
        } else {
          retryTime++;
          request(configTemp, retryTime);
        }
      // if(code == 401)  如果token失效,想做无感刷新,在这里重新请求一次获取token,让token失效前正在请求还没有请求的接口保存在一个数组里面,等到token更新好,遍历数组将没有请求成功的接口继续请求,这里就可以实现无感刷新了
      return Promise.reject(error);
      // 使用 Promise.reject 手动抛出异常,让 Promise.all 并发请求的方法中的 catch 捕获该异常,从而实现重试机制
      // return Promise.reject(error);
    });
}

// 取消请求 具体参看官网
// const controller = new AbortController();
// const cancelAxios = () => {
//   controller.abort();
// };
let retryTime = 1; // 重试次数

/**
 * 封装 get 请求方法
 * @param url
 * @param params 对象
 * @param other 其他参数,(上传下载文件流,请求终止等参数) 比如  { responseType: 'blob' }  {   signal: controller.signal }
 * @returns
 */
export function get(url: string, params = {}, other?: any) {
  return request(
    {
      url,
      params,
      method: 'get',
      ...other,
    },
    retryTime,
  );
}

/**
 * 封装 post 请求方法
 * @param url
 * @param params 对象
 * @param other 其他参数,(上传下载文件流,请求终止等参数) 比如  { responseType: 'blob' }  {   signal: controller.signal }
 * @returns
 */
export function post(url: string, data = {}, other?: any) {
  return request(
    {
      url,
      data,
      method: 'post',
      ...other,
    },
    retryTime,
  );
}

// 封装 put 请求方法
export function put(url: string, data = {}) {
  return request(
    {
      url,
      data,
      method: 'put',
    },
    retryTime,
  );
}

// 封装 delete 请求方法
export function del(url: string, params = {}) {
  return request(
    {
      url,
      params,
      method: 'delete',
    },
    retryTime,
  );
}


使用方法

index.ts 和 request.ts 中的方法使用

import http from '../../index';
import { formatQuery } from '../../../libs/utils/format';
import { get, post, put, del } from '../../request';

const prefix: string = '/meta/tasks';


/**
 * 将对象转化为URL的查询字符串
 * @param q 查询对象
 * @returns URL的查询字符串
 */

export const formatQuery = (q: any) => {
  let query = '';
  Object.keys(q).forEach((key) => {
    if (q[key] !== '' && q[key] !== undefined) {
      query += `${key}=${q[key]}&`;
    }
  });
  return query.substring(0, query.length - 1);
};

export const getTasks = (
  status: string | undefined,
  page: number,
  pageSize: number,
  signal: any,
  sorterName?: string,
  sorterType?: string,
  sixteen?: string,
  generation?: string,
  name?: string,
) => {
  return http.get(
    `${prefix}?${formatQuery({
      query: status !== '' && status !== undefined ? `status:${status}` : '',
      page,
      pageSize,
      sorterName,
      sorterType,
      sixteen,
      generation,
      name,
    })}`,
  );
};

export const getTasks2 = (
  status: string | undefined,
  page: number,
  pageSize: number,
  signal: any,
  sorterName?: string,
  sorterType?: string,
  sixteen?: string,
  generation?: string,
  name?: string,
) => {
  let params = {
    query: status !== '' && status !== undefined ? `status:${status}` : '',
    page,
    pageSize,
    sorterName,
    sorterType,
    sixteen,
    generation,
    name,
  };
  return get(prefix, params, { signal });
};


.

fetch 的使用

fetch cdn参考文档

Fetch 提供了对 Request 和 Response(以及其他与网络请求有关的)对象的通用定义。这将在未来更多需要它们的地方使用它们,无论是 service worker、Cache API,又或者是其他处理请求和响应的方式,甚至是任何一种需要你自己在程序中生成响应的方式(即使用计算机程序或者个人编程指令)。

它同时还为有关联性的概念,例如 CORS 和 HTTP Origin 标头信息,提供一种新的定义,取代它们原来那种分离的定义。

发送请求或者获取资源,请使用 fetch() 方法。它在很多接口中都被实现了,更具体地说,是在 Window 和 WorkerGlobalScope 接口上。因此在几乎所有环境中都可以用这个方法获取资源。

fetch() 强制接受一个参数,即要获取的资源的路径。它返回一个 Promise,该 Promise 会在服务器使用标头响应后,兑现为该请求的 Response——即使服务器的响应是 HTTP 错误状态。你也可以传一个可选的第二个参数 init(参见 Request)。

一旦 Response 被返回,有许多方法可以获取主体定义的内容以及如何处理它。

你也可以通过 Request() 和 Response() 构造函数直接创建请求和响应。但是我们不建议这么做,它们更可能被创建为其他的 API 操作的结果(比如,service worker 中的 FetchEvent.respondWith)。

在这里插入图片描述

用法

fetch("http://example.com/movies.json")
  .then((response) => response.json())
  .then((data) => console.log(data));

// Example POST method implementation:
async function postData(url = "", data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: "POST", // *GET, POST, PUT, DELETE, etc.
    mode: "cors", // no-cors, *cors, same-origin
    cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
    credentials: "same-origin", // include, *same-origin, omit
    headers: {
      "Content-Type": "application/json",
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: "follow", // manual, *follow, error
    referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
    body: JSON.stringify(data), // body data type must match "Content-Type" header
  });
  return response.json(); // parses JSON response into native JavaScript objects
}

postData("https://example.com/answer", { answer: 42 }).then((data) => {
  console.log(data); // JSON data parsed by `data.json()` call
});

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
axios是一个基于Promise的HTTP客户端,可以在浏览器和Node.js中使用。二次封装axios可以方便我们在项目中使用统一的请求拦截响应拦截,提高代码复用率和可维护性。 以下是一个axios二次封装的示例代码: ```javascript import axios from 'axios' // 创建axios实例 const instance = axios.create({ baseURL: 'http://api.example.com', // 设置请求的baseURL timeout: 10000 // 设置请求超时时间 }) // 请求拦截器 instance.interceptors.request.use(config => { // 在请求发送之前做些什么 // 可以在请求头中添加token等信息 return config }, error => { // 对请求错误做些什么 return Promise.reject(error) }) // 响应拦截器 instance.interceptors.response.use(response => { // 对响应数据做些什么 return response.data }, error => { // 对响应错误做些什么 return Promise.reject(error) }) export default instance ``` 在上面的代码中,我们通过create方法创建了一个axios实例,然后分别添加了请求拦截器和响应拦截器。在请求拦截器中,我们可以对请求进行一些处理,比如在请求头中添加token等信息;在响应拦截器中,我们可以对响应数据进行一些处理,比如统一处理错误信息。 最后,我们将封装好的axios实例导出,就可以在项目中使用了。例如: ```javascript import axios from './axios' axios.get('/user').then(res => { console.log(res) }).catch(err => { console.log(err) }) ``` 这样,我们就可以在项目中使用统一的请求拦截响应拦截了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜空孤狼啸

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值