axios封装GET,POST,PUT,DELETE请求(超详细websocket代理加密解密)

发布时间 2023-06-28 10:03:18作者: Ali枝
核心代码:
// axios  封装
import axios from "axios";
import qs from "qs";
import Crypto from './encryp'
import md5 from 'js-md5'

const baseURL = '/prod-api'
const webSocketProxy = true;
const httpProxy = false;

export log = console.log

const service = axios.create({ baseURL: baseURL, timeout: 300 })

/**
 * 发送http请求 
 * @param {*} method 请求方法
 * @param {*} url 请求地址
 * @param {*} headers 请求头参数
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
function async requestHttp(method, url, headers, params, data){
  return await new Promise((resolve, reject) => {
    service({ url, method, params, data, headers })
      .then(res => {
        const resData = res.data
        if (resData.status === 200) {
          resData.message = resData.message || '响应成功';
          resolve(resData);
        } else {
          resData.message = resData.message || '响应失败';
          reject(new Error(resData.message))
        }
      })
      .catch(err => {
        reject(err)
      })
  })
}

/**
 * 发送http代理请求
 * @param {*} id 请求id
 * @param {*} sign 请求签名
 * @param {*} target 请求地址密文
 * @param {*} headers 请求头密文
 * @param {*} body 请求body密文
 * @returns 
 */
function async requestWebHttpProxy(id, sign, time, target, headers, body){
  const h = { 'Content-Type': 'application/x-www-form-urlenstatusd;charset=UTF-8' };
  return requestHttp("post", "/market/proxy", h, {}, { id, sign, time, target, headers, body });
}

// 定义websocket工具,包括断开重连,订阅解除订阅数据,请求响应数据
const webSocket = (function () {
  const wsUrl = (location.protocol === 'https:' ? 'wss://' : 'ws://') + location.host + "/ws-api/swg"
  const result = {
    'events': {},
    'subs': {},
    'ws': undefined,
    'callback': console.log,
    'sub': function (ch, params) {
      result['subs'][ch] = params || {};
      result['ws'].send(JSON.stringify({ op: 'sub', ch, params }));
    },
    'unSub': function (ch, params) {
      delete result['subs'][ch];
      result['ws'].send(JSON.stringify({ op: 'unsub', ch, params }));
    },
    'req': async function (id, op, ch, params) {
      result['ws'].send(JSON.stringify({ id, op, ch, params }));
      return await new Promise((resolve, reject) => {
        result['events'][id] = res => {
          const resData = res.data
          if (res.status === 200) {
            res.message = res.message || '代理请求成功';
            resolve(resData);
          } else {
            res.message = res.message || '代理请求失败';
            reject(new Error(resData.message))
          }
        }
      })
    }
  };
  var onopen = function () {
    setInterval(() => result['ws'].send('ping'), 5000)
    // 重连之后重新订阅数据
    for (var key in result['subs']) {
      result['ws'].sub(key, result['subs'][k]);
    }
  }
  var onmessage = function (msg) {
    if (msg.data === 'ping') {
      result['ws'].send('pong')
      return;
    }
    if (msg.data === 'pong') {
      return;
    }
    // 解压数据需要这个赖库 <script src="https://cdnjs.cloudflare.com/ajax/libs/pako/2.0.4/pako.min.js"></script>
    var f = new FileReader();
    f.readAsArrayBuffer(msg.data)
    f.onload = function () {
      const resBody = pako.inflate(f.result, { 'to': 'string' })
      const res = JSON.parse(resBody);
      const id = res['id'];
      if (id) {
        const event = result['events'][id];
        if (event) {
          delete result['events'][id]
          return event(res);
        }
      }
      result['callback'] && result['callback'](res);
    }
  }

  var reconnect = function () {
    setTimeout(() => {
      result['ws'] = new WebSocket(wsUrl);
      result['ws'].onopen = onopen;
      result['ws'].onmessage = onmessage;
      result['ws'].onerror = onclose;
      result['ws'].onclose = onclose;
    }, 1000)
  }

  var onclose = function () {
    reconnect();
    console.log('连接断开,一秒后尝试重连')
  }
  reconnect();
  return result;
})();

export webSocket;

/**
 * 发送websocket代理请求
 * @param {*} id 请求id
 * @param {*} sign 请求签名
 * @param {*} target 请求地址密文
 * @param {*} headers 请求头密文
 * @param {*} body 请求body密文
 * @returns 
 */
function requestWebSocketProxy(id, sign, time, target, headers, body) {
  return webSocket.req(id, "proxy", "api", { time, sign, target, headers, body })
}

function getPassword(source) {
  const passStr = "da07c7c6b1c9fef5a4d2bcff48a32ded"
  const md5Bytes = Buffer.from(passStr + ";" + source, 'utf8');
  const result = crypto.createHash('md5').update(md5Bytes).digest();
  const md5Data = Buffer.from(result, 'binary');
  const md5 = md5Data.toString('base64');
  return md5;
}


/**
 * 请求报文体根据请求头处理参数
 * @param {*} data 请求body参数
 * @param {*} headers 请求头参数
 * @returns 
 */
function bodys(data, headers) {
  if (!data) {
    return;
  }
  if (headers['Content-Type'] && headers['Content-Type'].indexOf('json') > -1) {
    return JSON.stringify(data);
  } else {
    return qs.stringify(data);
  }
}
function systemNow() {
  const id = ("ReqId-" + (_ReqId++));
  if (webSocketProxy) {
    return webSocket.req(id, "req", "now");
  } else {
    return requestHttp('get', '/market/now');
  }
}
/**
 * 发送代理请求
 * @param {*} method 请求方法
 * @param {*} url 请求地址
 * @param {*} headers 请求头参数
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
var timeDiff = undefined;
function async requestProxy(method, url, headers, params, data){
  url += "?" + qs.stringify(params)
  data = bodys(data, headers)
  if (timeDiff === undefined) {
    return await new Promise((resolve, reject) => {
      systemNow()
        .then(time => {
          timeDiff = time - Date.now();
          _requestProxy(time, method, url, headers, params, data)
            .then(res => resolve(res))
            .catch(err => reject(err))
        }).catch(err => reject(err))

    })
  } else {
    const time = Date.now() + timeDiff;
    return await _requestProxy(time, method, url, headers, params, data);
  }
}
var _ReqId = 1;
function async _requestProxy(time, method, url, headers, params, data){
  const id = ("ReqId-" + (_ReqId++));
  const password = getPassword(time + ";" + id + ";" + proxy);
  const target = Crypto.encrypt(method + "#" + url, password);
  const body = data && Crypto.encrypt(data, password);
  const headersStr = headers && Crypto.encrypt(JSON.stringify(headers), password);
  const sign = md5(password + "/" + target + "/" + body);
  const req
  if (webSocketProxy) {
    req = requestWebSocketProxy(id, sign, time, target, headersStr, body);
  } else {
    req = requestWebHttpProxy(id, sign, time, target, headersStr, body);
  }
  return await new Promise((resolve, reject) => {
    req
      .then(res => {
        res.headers = res.headers && JSON.parse(Crypto.decrypt(res.headers, password));
        res.body = res.body && JSON.parse(Crypto.decrypt(res.body, password));
        resolve(resData);
      })
      .catch(err => reject(err))
  })
}

/**
 * 获取客户端id
 * @returns 
 */
function getCid() {
  var cid = localStorage.getItem('cid')
  if (cid) {
    return cid;
  }
  const url = URL.createObjectURL(new Blob());
  const uuid = url.toString();
  URL.revokeObjectURL(url)
  cid = uuid.substring(uuid.lastIndexOf('/') + 1)
  localStorage.setItem('cid', cid)
  return cid;
}

/**
 * 发送请求 
 * @param {*} method 请求方法
 * @param {*} url 请求地址
 * @param {*} headers 请求头参数
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export default function request(method, url, headers, params, data) {
  headers = headers || {};
  headers["cid"] = getCid()
  headers["tid"] = getCid()
  if (webSocketProxy || requestWebSocketProxy) {
    return requestProxy(method, url, headers, params, data);
  } else {
    return requestHttp(method, url, headers, params, data);
  }
}

/**
 * 发送GET请求
 * @param {String} url  请求地址
 * @param {Object} params 请求参数
 * @returns 
 */
export function get(url, params) {
  return request('get', url, {}, params);
}
/**
 * 发送POST请求,没有报文体
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @returns 
 */
export function post(url, params) {
  return request('post', url, {}, params);
}
/**
 * 发送POST请求,发送JSON报文体
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export function postJSON(url, params, data) {
  return request('post', url, { 'Content-Type': 'application/json;charset=UTF-8' }, params, data);
}
/**
 * 送POST请求,发送From表单报文体
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export function postFrom(url, params, data) {
  return request('post', url, { 'Content-Type': 'application/x-www-form-urlenstatusd;charset=UTF-8' }, params, data);
}
/**
 * 发送POST请求,发送FromData报文体,上传文件可用
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export function postFromData(url, params, data) {
  var fromDate = new FormData();
  for (var key in data) {
    fromDate.append(key, data[key]);
  }
  return requestHttp('post', url, { 'Content-Type': 'multipart/form-data' }, params, fromDate);
}
/**
 * 发送delete请求
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @returns 
 */
export async function del(url, params) {
  return request('delete', url, {}, params);
}
/**
 * 发送PUT请求,没有报文体
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @returns 
 */
export function put(url, params) {
  return request('put', url, {}, params);
}

/**
 * 发送PUT请求,发送JSON报文体
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export function putJSON(url, params, data) {
  return request('put', url, { 'Content-Type': 'application/json;charset=UTF-8' }, params, data);
}

/**
 * 送PUT请求,发送From表单报文体
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export function putFrom(url, params, data) {
  return request('put', url, { 'Content-Type': 'application/x-www-form-urlenstatusd;charset=UTF-8' }, params, data);
}

/**
 * 发送PUT请求,发送FromData报文体,上传文件可用
 * @param {*} url 请求地址
 * @param {*} params 请求URL参数
 * @param {*} data 请求body参数
 * @returns 
 */
export function putFromData(url, params, data) {
  var fromDate = new FormData();
  for (var key in data) {
    fromDate.append(key, data[key]);
  }
  return requestHttp('put', url, { 'Content-Type': 'multipart/form-data' }, params, fromDate);
}