Files
rn-app/utils/network/helper.ts
2025-11-06 16:37:01 +08:00

435 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { HmacMD5 } from 'crypto-js';
import Base64 from 'crypto-js/enc-base64';
import Latin1 from 'crypto-js/enc-latin1';
import md5 from 'md5';
import { AxiosResponse } from 'axios';
import * as des from './des';
import NetworkError from './error';
import { toNumber, toString, startsWith, isString, isNumber } from 'lodash-es';
import { NetworkTypeEnum } from '@/constants/network';
import appConfig from '../config';
// import NetworkError from './error'
// import { storeToRefs, useTenantStore, useUserStore, useAppStore, start } from '../index';
// import { isMobile, getBetPlatform } from '@star/utils';
// import { langToNum } from '@star/languages';
// 请求到的数据返回
export type NetworkResponse<T> = {
type: NetworkTypeEnum;
data: T;
};
export const getBetPlatform = (isReturnIndex = false) => {
// 5=PC; 7=HOMESCREEN_IOS; 6=HOMESCREEN_ANDROID; 4=H5_IOS 3=IOS 2=H5_ANDROID; 1=ANDROID 8=马甲包
return 'H5_IOS';
// const platform = new URLSearchParams(window.location.search).get('platform');
// if (platform) {
// return platform?.includes('IOS') ? 'IOS' : platform?.includes('ANDROID') ? 'ANDROID' : '';
// }
// if (isAppMJB()) {
// return 'APPS_ANDROID';
// }
// if (isPWA()) {
// if (isIOS()) {
// return isReturnIndex ? 4 : 'HS_IOS';
// } else {
// return isReturnIndex ? 2 : 'HS_ANDROID';
// }
// }
// if (isAndroid()) {
// if (BASE_CONFIG.appVersion > 0) {
// return isReturnIndex ? 1 : 'ANDROID';
// } else {
// return isReturnIndex ? 2 : 'H5_ANDROID';
// }
// }
// if (isIOS()) {
// if (BASE_CONFIG.appVersion > 0) {
// return isReturnIndex ? 3 : 'IOS';
// } else {
// return isReturnIndex ? 4 : 'H5_IOS';
// }
// }
// return isReturnIndex ? 5 : 'PC';
};
const uuid = (len: number, radix: number) => {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
const uuid: any[] = [];
radix = radix || chars.length;
if (len) {
// Compact form
for (let i = 0; i < len; i++) uuid[i] = chars[0 | (Math.random() * radix)];
} else {
// rfc4122, version 4 form
/* eslint-disable */
let r;
// rfc4122 requires these characters
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
// Fill in random data. At i==19 set the high bits of clock sequence as
// per rfc4122, sec. 4.1.5
for (let i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | (Math.random() * 16);
uuid[i] = chars[i == 19 ? (r & 0x3) | 0x8 : r];
}
}
/* eslint-enable */
}
return uuid.join('');
};
// 格式化要发送的数据
export const formatSendData = (data: any, type: number = 0) => {
// url code
if (type === 0) {
const arr: any[] = [];
for (const k in data) {
const v = data[k];
if (v instanceof Array) {
for (const subK in v) {
arr.push(`${k}[]=${v[subK]}`);
}
} else {
arr.push(`${k}=${data[k]}`);
}
}
return arr.join('&');
} else if (type === 2) {
return data.join('/');
}
// json
return JSON.stringify(data);
};
export const getP = (p: any) => {
return HmacMD5(p, '7NEkojNzfkk=').toString();
};
export const enD = (rk: string, str: string) => {
const enc = des.des(rk, str, 1, 0, null, 1);
return Base64.stringify(Latin1.parse(enc));
};
export const dnD = (rk: string, str: string) => {
const s = Latin1.stringify(Base64.parse(str));
const d = des.des(rk, s, 0, 0, null, 1);
return d;
};
export const enP = (rk: string, vk: string, t: number) => {
const enc = des.des(vk, rk + t, 1, 0, null, 1);
return Base64.stringify(Latin1.parse(enc));
};
export const dnP = (vk: string, str: string) => {
const s = Latin1.stringify(Base64.parse(str));
const p = des.des(vk, s, 0, 0, null, 1);
return p;
};
export const enC = (rk: string, vk: string, m: string) => {
const enc = HmacMD5(m + rk, vk);
return Base64.stringify(enc);
};
export const getRequestKey = (cmdId: number, data: any) => {
return `${cmdId}&${data ? md5(JSON.stringify(data)) : ''}`;
};
// 加工请求数据
export const transformRequest = (config: any) => {
const { headerType = 2, paramType = 0, cmdId, tid, ...reset } = config.headers;
const headers: Record<string, any> = {};
// const { tenantInfo } = storeToRefs(useTenantStore());
// const { userInfo } = storeToRefs(useUserStore());
// const { language } = storeToRefs(useAppStore());
const t = new Date().getTime();
const rk = md5(toString(Math.random() + t)).substring(0, 8);
const vk = appConfig.app.vk as string;
const pwds = enP(rk, vk, t);
const tenantInfo = {
tid: 3,
};
let userInfo = {
cust_id: '',
cust_name: '',
access_token: ''
};
// if (['17', '3310052', '310111', '310122', '310400', '4', '402', '401', '310635'].includes(cmdId)) {
// const publicParams = {
// tid: tid ?? tenantInfo.value?.tid ?? '',
// cust_id: (config.data?.cust_id === 0 ? '0' : '') || userInfo?.value?.cust_id || '',
// cust_name: (config.data?.cust_name === 0 ? '0' : config.data?.cust_name) || userInfo?.value?.cust_name || '',
// oper_code: (config.data?.cust_id === 0 ? '0' : '') || userInfo?.value?.cust_id || '',
// oper_name: (config.data?.cust_name === 0 ? '0' : config.data?.cust_name) || userInfo?.value?.cust_name || '',
// };
// const localData = localStorage.getItem('publicData') || '';
// const publicData = localData ? JSON.parse(localData) : {};
// if (['17', '3310052', '310111', '310122'].includes(cmdId)) {
// if (['4', '402', '401'].includes(cmdId)) {
// publicParams.tid = publicParams?.tid.toString();
// publicData.client_type = publicData?.client_type.toString();
// publicData.oper_class_type = publicData?.oper_class_type.toString();
// publicData.oper_source_type = publicData?.oper_source_type.toString();
// publicData.mark = publicData?.mark.toString();
// // publicData.ori_value = "";
// // publicData.new_value = "";
// // publicData.trans_type = "101";
// // publicData.busi_type = "206";
// // publicData.oper_method = "11";
// }
//
// Object.assign(config.data, publicParams, publicData);
// } else if (['310400'].includes(cmdId)) {
// console.log('publicParams', publicParams, publicData);
// config.data.memberOperInfoVo = {
// ...publicParams,
// ...publicData,
// ori_value: '',
// new_value: '',
// oper_method: 1,
// trans_type: 105,
// busi_type: 222,
// };
// } else if (['310635', '4', '402', '401'].includes(cmdId)) {
// config.data.trans_type = '101';
// config.data.client_type = publicData.client_type;
// config.data.browser_brand = publicData.browser_brand;
// config.data.os_name = publicData.os_name;
// config.data.os_version = publicData.os_version;
// config.data.device_platform = publicData.device_platform;
// config.data.device_model = publicData.device_model;
// config.data.device_number = publicData.device_number;
// config.data.device_fingerprint = publicData.device_fingerprint;
// }
//
// console.log('config.data', config.data);
// }
const sendStr = enD(rk, formatSendData(config.data, toNumber(paramType)));
const sendDateStr = enD(rk, t.toString());
const checkOr = enC(rk, vk, sendDateStr);
headers.cmdId = cmdId;
headers.aseqId = appConfig.app.aseqId;
headers.nc = appConfig.app.nc;
headers.tid = tid ?? tenantInfo.tid ?? '';
// 试玩游戏cust_id=0 header需要保持一致
headers.custId = (config.data?.cust_id === 0 ? '0' : '') || userInfo?.cust_id || '';
headers.reqId = uuid(32, 16);
// headers.isMobileOpen = isMobile() ? '1' : '0';
headers.isMobileOpen = '1';
// headers.languageNum = langToNum(language.value);
headers.languageNum = 0;
headers.project = 'tiyu-app';
headers.platform = getBetPlatform(); // 哪端
headers.checkOr = checkOr;
headers.pwds = pwds;
headers.datetime = t;
headers.tbc = md5(t + 'fT6phq0wkOPRlAoyToidAnkogUV7tBBD');
headers.reqKey = getRequestKey(cmdId, config.data); // 每一个接口请求的唯一key前端用
if (toNumber(headerType) === 1) {
const grantType = 'password';
const scope = 'read write';
const signature = `react_clientgrant_type=${grantType}scope=${scope}cmd_id=${cmdId}react`;
headers.signature = md5(signature);
} else if (toNumber(headerType) === 2) {
const authorization = `Bearer ${userInfo?.access_token || ''}`;
const signature = `react_clientauthorization=${authorization}cmd_id=${cmdId}react`;
headers.authorization = authorization;
headers.signature = md5(signature);
} else if (toNumber(headerType) === 3) {
const grantType = 'refresh_token';
const scope = '';
const signature = `react_clientgrant_type=${grantType}scope=${scope}cmd_id=${cmdId}react`;
headers.signature = md5(signature);
}
// console.log(headers, cmdId, '<------ request headers');
// localStorage.getItem('SHOW_DATA') &&
// console.error(cmdId, '最终请求参数', formatSendData(config.data, toNumber(paramType))); // 查看最终请求参数
console.log(cmdId, 'request data --->', config.data);
return {
headers: { ...reset, ...headers },
data: sendStr,
};
};
// 解释响应数据
export const parseResponse = (response: AxiosResponse): Promise<NetworkResponse<any>> => {
try {
const { headers, data } = response;
const reqHeaders = response.config?.headers || {};
// if (reqHeaders.cmdId == 310122) {
// console.log(data, reqHeaders.cmdId, '<<<<<<<<<<<<<<<<<<<<<<<<<< parseResponse data');
// }
if (isString(data) && data.length > 0 && !startsWith(data, '<html>')) {
// 检查 headers 是否存在必要的属性
if (!headers || !headers.pwds || !headers.datetime) {
console.error('Response headers missing required fields:', headers);
throw new NetworkError({
key: '',
tag: 'Network error 0',
info: '响应头缺少必要字段',
origin: '',
cmd: reqHeaders.cmdId,
});
}
const drk = dnP(appConfig.app.vk, headers.pwds).substring(0, 8);
const dm = dnD(drk, data);
const dc = enC(drk, appConfig.app.vk, enD(drk, toString(headers.datetime)));
// if (reqHeaders.cmdId == 310122) {
// console.log(dm, JSON.parse(dm), reqHeaders.cmdId);
// }
// localStorage.getItem('SHOW_DATA') &&
// console.error(reqHeaders.cmdId, dm ? JSON.parse(dm) : dm); // 查看请求返回的数据
if (!dm) {
throw new NetworkError({
key: '',
tag: 'Network error 1',
info: '数据为空',
origin: '',
cmd: reqHeaders.cmdId,
});
}
if (dc !== headers.checkor) {
throw new NetworkError({
key: '',
tag: 'Network error 2',
info: '返回数据异常',
origin: '',
cmd: reqHeaders.cmdId,
});
}
const resData: any = JSON.parse(dm);
console.log(
JSON.parse(JSON.stringify(resData)),
reqHeaders.cmdId,
'<<<<<<<<<<<<<<<<<<<<<<<<<< parseResponse resData'
);
if (resData) {
if (resData.exLevel) {
// 接口请求的错误处理
let err: any;
// 预存奖励领取的时候 返回'0'提示
if ([724209].includes(+reqHeaders.cmdId)) {
throw {
key: '',
tag: 'Network error 3',
info: resData.exMessage,
origin: resData,
cmd: reqHeaders.cmdId,
code: resData.exCode,
};
} else {
err = new NetworkError({
key: '',
tag: 'Network error 3',
info: resData.exMessage,
origin: resData,
cmd: reqHeaders.cmdId,
code: resData.exCode,
});
}
// 版本号不对,强制更新
if (err.code === 1108) {
err.update = true;
} else if ([1200, 1201, 1109, 1112, 1202, 1007].includes(+err.code)) {
// 1200 refresh_token错误
// 1201 access_token错误
// 1112 IP限制
err.logout = true; // 退出登录
err.tag = 'Network error 4';
err.logoutMessage = '返回异常';
}
throw err;
} else if (resData.error) {
throw new NetworkError({
key: '',
tag: 'Network error 5',
info: resData.error_description,
origin: resData,
cmd: reqHeaders.cmdId,
code: resData.exCode,
});
} else if (resData.response_code === '0') {
// 回收第三方金额 没有的的时候 也是返回'0'
// 预存奖励领取的时候 返回'0'提示
if ([3911381, 724209].includes(+reqHeaders.cmdId)) {
resData.response_code = '1';
} else {
throw new NetworkError({
key: '',
tag: 'Network error 8',
info: resData.msg || '操作失败',
origin: resData,
cmd: reqHeaders.cmdId,
code: resData.exCode,
});
}
}
} else {
if (!isNumber(toNumber(resData))) {
throw new NetworkError({
key: '',
tag: 'Network error 1',
info: '数据为空',
origin: '',
cmd: reqHeaders.cmdId,
});
}
}
return Promise.resolve({ type: NetworkTypeEnum.SUCCESS, data: resData });
} else {
localStorage.getItem('SHOW_DATA') && console.error(reqHeaders.cmdId, data); // 查看请求返回的原始数据
throw new NetworkError({
key: '',
tag: 'Network error 7',
info: '请求没有返回任何数据',
// origin: context || response.toString(),
cmd: reqHeaders.cmdId,
code: -1,
});
}
} catch (e) {
// // 404等错误处理
// if (typeof context === 'object') {
// errStr = JSON.stringify(context);
// } else {
// const arr = context.match(/title[\s\S]*?title/g);
// if (arr && arr.length !== 0) {
// errStr = arr[0].replace(/title>/g, '').replace(/<\/title/g, '');
// }
// }
// let logout = false;
// if (errStr.indexOf('invalid_token') !== -1) {
// logout = true;
// }
// // 类似这种错误的时候 跳到登录页 "error":"access_denied" "error":"unauthorized"
// if (errStr.indexOf('access_denied') !== -1 || errStr.indexOf('unauthorized') !== -1) {
// logout = true;
// }
// err = new NetworkError({
// key: key,
// tag: 'Network error 6',
// info: errStr,
// origin: context,
// cmd: reqHeaders.cmdId,
// code: -1,
// logout: logout,
// });
return Promise.reject({ type: NetworkTypeEnum.ERROR, data: e });
}
};