前言
websocket, localStorage, sessionStorage, cookie, axios
这些都是前端常用的工具,这里整合了所有的库,避免每次都要麻烦的找一遍。
分类
按类型分了三类:
websocket
文件名叫websocket.js
localStorage, sessionStorage, cookie
这仨共一个文件, 叫persistence.js
, 持久化。如果叫store容易与状态管理的混淆axios
文件名叫request.js
1. websocket.js
class Socket {
constructor(params) {
if (!this.isSupportWebSocket()) {
console.error('!!!浏览器不支持websocket!!!');
return;
}
this.websocket = null;
this.params = params;
this.createWebSocket(params);
}
isSupportWebSocket() {
const socket = window.WebSocket || window.MozWebSocket;
return !!socket;
}
/**
* 创建并初始化WebSocket连接
*
* @param {Object} options - 连接参数对象
* @param {string} options.url - WebSocket服务器地址
* @param {Function} [options.onopen] - 连接成功的回调函数
* @param {Function} options.onmessage - 接收到消息的回调函数
* @param {Function} [options.onerror] - 发生错误的回调函数
* @param {Function} [options.onclose] - 连接关闭的回调函数
* @param {boolean} [options.isReconnect=true] - 是否自动重连,默认为true
* @param {number} [options.timer] - 心跳保活时间间隔(毫秒), 若为0,则不进行心跳保活
*/
createWebSocket({
url,
onopen,
onmessage,
onerror,
onclose,
isReconnect = true,
timer
}) {
if (url !== undefined) {
if (!/^wss?:\/\//.test(url)) {
// 自动补协议头
const protocol = location.protocol === 'http:' ? 'ws://' : 'wss://';
url = protocol + url;
}
try {
this.websocket = new WebSocket(url);
this.websocket.onopen = (e) => {
console.log('WebSocket 连接成功');
parseInt(timer) && this.keepAlive(parseInt(timer));
onopen instanceof Function && onopen(e);
};
this.websocket.onmessage = (e) => {
onmessage instanceof Function && onmessage(e.data);
};
this.websocket.onclose = (e) => {
console.log('WebSocket 连接关闭', e);
// 非正常关闭的重连
const isAbnormalClose = e.code !== 1000 || e.wasClean === false;
if (isReconnect && isAbnormalClose) {
this.doReconnect();
}
onclose instanceof Function && onclose(e);
};
this.websocket.onerror = (e) => {
console.log('WebSocket 连接异常', e);
isReconnect && this.doReconnect();
onerror instanceof Function && onerror(e);
};
} catch (e) {
console.log('WebSocket 创建失败', e);
isReconnect && this.doReconnect();
}
}
}
// 发送消息
send(message) {
if (!this.websocket || this.websocket.readyState !== 1) {
console.log('websocket连接失败, 无法发送消息');
return;
}
this.websocket.send(JSON.stringify(message));
}
// 手动关闭socket
close() {
clearInterval(this.keepAliveTimer);
clearTimeout(this.reconnectTimer);
this.websocket.close();
}
// websocket心跳保活
keepAlive(timer) {
this.keepAliveTimer = setInterval(() => {
this.send({ type: 'keepAlive' });
}, timer);
}
// 异常或非正常关闭, 则重连
doReconnect() {
if (this.isReconnecting) return;
this.isReconnecting = true;
clearTimeout(this.reconnectTimer);
this.reconnectTimer = setTimeout(() => {
this.createWebSocket(this.params);
this.isReconnecting = false;
}, 6000);
}
}
export default Socket;
用法:
import Socket from '@/utils/websocket';
const options = {
url: 'ws://1.1.1.1:8000',
timer: 15000,
onmessage: (res) => {
// 接收数据后回调
},
};
const socket = new Socket(options);
socket.send({xx:'xx'});
2. persistence.js
export const Cookie = {
getCookies: function (key) {
var arr = document.cookie.split('; ');
var obj = {};
arr.forEach((item) => {
const [keyName, keyValue] = item.split('=');
obj[keyName] = keyValue;
});
return key ? obj[key] : obj;
},
get: function (key) {
return this.getCookies(key);
},
// 默认30天, 单位秒
set: function (key, value, time = 30 * 24 * 60 * 60) {
var date = Now.Date().getTime() + time * 1000;
document.cookie = key + '=' + value + ';expires=' + new Date(date).toUTCString();
},
remove: function (key) {
var date = new Date().getTime() - 1000;
document.cookie = key + '=;expires=' + new Date(date).toUTCString();
},
};
export const Local = {
set(key, val) {
localStorage.setItem(key, JSON.stringify(val));
},
get(key) {
let json = localStorage.getItem(key);
return JSON.parse(json);
},
remove(key) {
localStorage.removeItem(key);
},
clear() {
localStorage.clear();
},
};
export const Session = {
set(key, val) {
sessionStorage.setItem(key, JSON.stringify(val));
},
get(key) {
let json = sessionStorage.getItem(key);
return JSON.parse(json);
},
remove(key) {
sessionStorage.removeItem(key);
},
clear() {
sessionStorage.clear();
},
};
用法:
import { Local, Session, Cookie } from '@/utils/persistence';
Local.set("key", 'abc');
Session.set("key", 'abc');
Cookie.set("key", 'abc');
Local.get("key");
Session.get("key");
Cookie.get("key");
3. request.js
axios的比较麻烦,因为各个业务的请求头和请求异常的结构都不一样,所以很难封装成统一的。这里把公共的都统一了起来,把不同的都剥离了出去。拷贝过去后,只要改几下几个地方即可。
baseUrl
基础请求头timeout
超时setRequestConfig
请求拦截器内处理config,一般是处理headers的Authorization即配置token和数据类型bizError
业务逻辑的异常,一般是特殊的code不正常otherError
包含4开头及5开头的错误,分别由request内拦截及response拦截,当然具体的要看后端怎么定义getData
code与data的结构, 每个公司的都不一样,要看着改。分两次部分,前端是正确的数据返回,最后的是异常的处理即bizError
import axios from 'axios';
const baseURL = '/api';
const timeout= 20000;
/** 设置请求拦截器 */
function setRequestConfig(config) {
// 添加token
// config.headers['Authorization'] = 'xxxx'
}
/** 业务逻辑错误 */
function bizError(err) {
console.error('bizError', err);
// 对鉴权及其它各种错误码进行处理
return Promise.reject(err);
}
/** 其他类型错误 */
function otherError(err) {
console.error('otherError', err);
return Promise.reject(err);
}
/** 返回请求数据或报异常 */
function getData(res) {
// 以下code与data的结构,以实际业务为准
const code = res.code || res.data?.code;
// 二进制数据则直接返回
if (res.request.responseType === 'blob') {
return res.data;
} else if (res.request.responseType === 'arraybuffer') {
return res;
}
if (code >= 200 && code < 300) {
return res.data;
}
return bizError(res);
}
/** ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 改上面的即可 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */
/** ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 下面的不要动 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
// 创建 axios 实例
const service = axios.create({
baseURL,
timeout
});
// 添加请求拦截器
service.interceptors.request.use(
(config) => {
// 处理header与token
// config.headers['Authorization'] = 'xxxx'
setRequestConfig(config);
return config;
},
(error) => {
// 请求错误的常见状态码以4开头,如401-请求超时、404-接口未找到
return otherError(error);
}
);
// 添加响应拦截器
service.interceptors.response.use(
(res) => {
return getData(res);
},
(error) => {
// 响应错误的常见状态码以5开头,如500-服务器错误、502-服务器重启等
return otherError(error);
}
);
// 导出 axios 实例
export default service;