文章目录
说明:这里是在老项目中继续封装的,如果新项目可以将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 提供了对 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
});