fix: TypeError: Cannot read properties of undefined (reading '__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED') at react-dom-CErclyH-.js:1:5784

This commit is contained in:
landaiqing
2024-05-05 01:20:15 +08:00
parent 9762e15b8b
commit bc569c7273
4 changed files with 38 additions and 317 deletions

View File

@@ -1,20 +1,5 @@
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'
import { message } from 'antd'
import {
aesDecrypt,
aesEncrypt,
get16RandomNum,
getRsaKeys,
rsaDecrypt,
rsaEncrypt,
} from '@/utils/encrypt/encrypt.ts'
import { handleLocalforage } from '@/utils/localforage'
let frontPrivateKey: any
let afterPublicKey: any
async function getAfterPublicKey() {
afterPublicKey = await handleLocalforage.getItem('afterPublicKey')
}
class Request {
private instance: AxiosInstance | undefined
@@ -23,43 +8,6 @@ class Request {
// 全局请求拦截
this.instance.interceptors.request.use(
(config) => {
if (config.headers['isEncrypt']) {
if (config.method === 'post' || config.method === 'put') {
let privateKey: any
let publicKey: any
getRsaKeys().then((res: any) => {
privateKey = res.privateKey
publicKey = res.publicKey
})
getAfterPublicKey()
frontPrivateKey = privateKey
//每次请求生成aeskey
const aesKey = get16RandomNum()
if (afterPublicKey) {
//用登陆后后端生成并返回给前端的的RSA密钥对的公钥将AES16位密钥进行加密
const aesKeyByRsa = rsaEncrypt(aesKey, afterPublicKey)
//使用AES16位的密钥将请求报文加密使用的是加密前的aes密钥
if (config.data) {
const data = aesEncrypt(aesKey, JSON.stringify(config.data))
config.data = {
data: data,
aeskey: aesKeyByRsa,
frontPublicKey: publicKey,
}
}
if (config.params) {
const data = aesEncrypt(aesKey, JSON.stringify(config.params))
config.params = {
params: data,
aeskey: aesKeyByRsa,
frontPublicKey: publicKey,
}
}
}
}
}
return config
},
(error) => {
@@ -71,20 +19,9 @@ class Request {
this.instance.interceptors.response.use(
(res) => {
if (res.data.code && res.data.code !== 200) {
message.error(res.data.message)
message.error(res.data.message).then()
return Promise.reject(res.data)
}
//后端返回的通过rsa加密后的aes密钥
const aesKeyByRsa: any = res.data.aesKeyByRsa
if (aesKeyByRsa) {
localStorage.setItem('afterPublicKey', aesKeyByRsa)
//通过rsa的私钥对后端返回的加密的aeskey进行解密
const aesKey: any = rsaDecrypt(aesKeyByRsa, frontPrivateKey)
//使用解密后的aeskey对加密的返回报文进行解密
res.data = JSON.parse(JSON.parse(aesDecrypt(aesKey, res.data)))
return res.data
}
return res.data
},
(error) => {
@@ -180,5 +117,29 @@ class Request {
})
})
}
put(url: string, data = {}) {
return new Promise((resolve, reject) => {
this.instance
?.put(url, data)
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
delete(url: string) {
return new Promise((resolve, reject) => {
this.instance
?.delete(url)
.then((res) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
})
}
}
export default Request

View File

@@ -1,233 +0,0 @@
import axios, {
AxiosError,
AxiosInstance,
AxiosRequestConfig,
AxiosResponse,
InternalAxiosRequestConfig,
} from 'axios'
import { message } from 'antd'
import router from '@/router'
// import { aesEncrypt, get16RandomNum, getRsaKeys, rsaEncrypt } from '@/utils/encrypt/encrypt.ts'
// 数据返回的接口
// 定义请求响应参数不含data
// interface Result {
// code: number
// msg: string
// }
// 请求响应参数包含data
// interface ResultData<T = never> extends Result {
// data?: T
// }
interface UploadFileItemModel {
name: string
value: string | Blob
}
type UploadRequestConfig = Omit<AxiosRequestConfig, 'url' | 'data'>
const URL = import.meta.env.VITE_API_BASE_URL
enum RequestEnums {
TIMEOUT = 20000,
OVERDUE = 600, // 登录失效
FAIL = 999, // 请求失败
SUCCESS = 200, // 请求成功
}
const config = {
// 默认地址
baseURL: URL as string,
// 设置超时时间
timeout: RequestEnums.TIMEOUT as number,
// 跨域时候允许携带凭证
withCredentials: true,
}
// let frontPrivateKey :string = ''
class RequestHttp {
// 定义成员变量并指定类型
service: AxiosInstance
public constructor(config: AxiosRequestConfig) {
// 实例化axios
this.service = axios.create(config)
/**
* 请求拦截器
* 客户端发送请求 -> [请求拦截器] -> 服务器
*/
this.service.interceptors.request.use(
(config: InternalAxiosRequestConfig | any) => {
if (localStorage.getItem('token')) {
const token = localStorage.getItem('token') || ''
return {
...config,
headers: {
'x-access-token': token, // 请求头中携带token信息
},
}
}
// if (config.headers['isEncrypt']) {
// config.headers['Content-Type'] = 'application/json;charset=utf-8'
// if (config.method === 'post' || config.method === 'put') {
// const { privateKey, publicKey } = await getRsaKeys()
// const afterPublicKey = sessionStorage.getItem('afterPublicKey')
// frontPrivateKey = privateKey
// //每次请求生成aeskey
// const aesKey = get16RandomNum()
// //用登陆后后端生成并返回给前端的的RSA密钥对的公钥将AES16位密钥进行加密
// const aesKeyByRsa = rsaEncrypt(aesKey, afterPublicKey)
// //使用AES16位的密钥将请求报文加密使用的是加密前的aes密钥
// if (config.data) {
// const data = aesEncrypt(aesKey, JSON.stringify(config.data))
// config.data = {
// data: data,
// aesKey: aesKeyByRsa,
// frontPublicKey: publicKey,
// }
// }
// if (config.params) {
// const data = aesEncrypt(aesKey, JSON.stringify(config.params))
// config.params = {
// params: data,
// aesKey: aesKeyByRsa,
// frontPublicKey: publicKey,
// }
// }
// }
// }
},
(error: AxiosError) => {
// 请求报错
return Promise.reject(error)
},
)
/**
* 响应拦截器
* 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
*/
this.service.interceptors.response.use(
(response: AxiosResponse) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
const { data, config } = response // 解构
if (data.code === RequestEnums.OVERDUE) {
// 登录信息失效应跳转到登录页面并清空本地的token
localStorage.setItem('token', '')
return Promise.reject(data)
}
// 全局错误信息拦截防止下载文件得时候返回数据流没有code直接报错
if (data.code && data.code !== RequestEnums.SUCCESS) {
message.error(data) // 此处也可以使用组件提示报错信息
return Promise.reject(data)
}
return data
},
(error: AxiosError) => {
const { response } = error
if (response) {
this.handleCode(response.status)
}
if (!window.navigator.onLine) {
message.error('网络连接失败')
// 可以跳转到错误页面,也可以不做操作
return router.push({
path: '/404',
})
}
},
)
}
handleCode(code: number): void {
switch (code) {
case 400:
message.error('请求错误(400)')
break
case 401:
message.error('未授权,请重新登录(401)')
break
case 403:
message.error('拒绝访问(403)')
break
case 404:
message.error('请求出错(404)')
break
case 408:
message.error('请求超时(408)')
break
case 500:
message.error('服务器错误(500)')
break
case 501:
message.error('服务未实现(501)')
break
case 502:
message.error('网络错误(502)')
break
case 503:
message.error('服务不可用(503)')
break
case 504:
message.error('网络超时(504)')
break
case 505:
message.error('HTTP版本不受支持(505)')
break
default:
message.error(`连接出错(${code})!`)
break
}
}
request<T = any>(config: AxiosRequestConfig): Promise<T> {
/**
* TODO: execute other methods according to config
*/
return new Promise((resolve, reject) => {
try {
this.service
.request<T>(config)
.then((res: any) => {
resolve(res)
})
.catch((err) => {
reject(err)
})
} catch (err) {
return Promise.reject(err)
}
})
}
// 常用方法封装
get<T = any>(config: AxiosRequestConfig): Promise<T> {
return this.request({ method: 'GET', ...config })
}
post<T = any>(config: AxiosRequestConfig): Promise<T> {
return this.request({ method: 'POST', ...config })
}
put<T = any>(config: AxiosRequestConfig): Promise<T> {
return this.request({ method: 'PUT', ...config })
}
delete<T = any>(config: AxiosRequestConfig): Promise<T> {
return this.request({ method: 'DELETE', ...config })
}
upload<T = string>(
fileItem: UploadFileItemModel,
config?: UploadRequestConfig,
): Promise<T> | null {
if (!import.meta.env.VITE_UPLOAD_URL) return null
const fd = new FormData()
fd.append(fileItem.name, fileItem.value)
let configCopy: UploadRequestConfig
if (!config) {
configCopy = {
headers: {
'Content-Type': 'multipart/form-data',
},
}
} else {
config.headers!['Content-Type'] = 'multipart/form-data'
configCopy = config
}
return this.request({ url: import.meta.env.VITE_UPLOAD_URL, data: fd, ...configCopy })
}
}
// 导出一个实例对象
export default new RequestHttp(config)

View File

@@ -1,13 +1,6 @@
import HomeIndex from '@/components/HomeIndex'
import { useEffect } from 'react'
import { handleLocalforage } from '@/utils/localforage'
export default () => {
useEffect(() => {
handleLocalforage.getItem('token').then((res: any) => {
console.log(JSON.parse(res))
})
}, [])
return (
<div>
<HomeIndex />

View File

@@ -145,19 +145,19 @@ export default defineConfig(({ mode }) => {
brotliSize: true, // 启用 brotli 压缩大小报告
chunkSizeWarningLimit: 2000, // chunk 大小警告的限制
watch: null, // 设置为 {} 则会启用 rollup 的监听器
rollupOptions: {
// 自定义底层的 Rollup 打包配置
output: {
chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
assetFileNames: '[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
manualChunks(id) {
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
},
},
},
// rollupOptions: {
// // 自定义底层的 Rollup 打包配置
// output: {
// chunkFileNames: 'js/[name]-[hash].js', // 引入文件名的名称
// entryFileNames: 'js/[name]-[hash].js', // 包的入口文件名称
// assetFileNames: '[ext]/[name]-[hash].[ext]', // 资源文件像 字体,图片等
// manualChunks(id) {
// if (id.includes('node_modules')) {
// return id.toString().split('node_modules/')[1].split('/')[0].toString()
// }
// },
// },
// },
},
server: {
proxy: {