// 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); }