【JS版本】前端工具整合: websocket, localStorage, sessionStorage, cookie, axios 统一封装

前言

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;

  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值