需要实现的功能
-
vue3+axios+useAxios网络请求封装 -
主域名返回多个接口域名,循环检测接口域名,状态码为200,即该域名可以用 -
解密后端返回的加密的数据
实现代码
-
简单的vue3+axios+useAxios网络请求封装
//useAxiosApi.ts
import { useAxios } from '@vueuse/integrations/useAxios' // 导入VueUse库中的useAxios函数
import axios from 'axios' // 导入Axios库
import { showToast } from 'vant'
import { useTokenStore } from '@/stores/token'
import { useIsLoggedStore } from '@/stores/isLogged'
//创建一个Axios实例
const instance = axios.create({
baseURL: 'https://uuiiiiiiew/', // 替换成你想要的baseURL
withCredentials: false, // 是否携带凭证,默认为false
timeout: 10000 // 请求超时时间,默认为5秒
})
instance.defaults.headers.common['Access-Control-Allow-Origin'] = '*'
//添加请求拦截器
instance.interceptors.request.use(
(config) => {
const tokenStore = useTokenStore()
const x_token = tokenStore.x_token
const isLoggedStore = useIsLoggedStore()
if (!x_token) {
isLoggedStore.logoutState()
}
if (x_token) {
config.headers = {
...config.headers,
Authorization: `Bearer ${x_token}`
}
}
return config
},
(error) => {
// 请求错误的处理逻辑
return Promise.reject(error)
}
)
instance.interceptors.response.use(
(response) => {
if (response.status !== 200 && response.status !== 201) {
// 401: Token过期;
if (response.status === 401) {
//返回登录页面
showToast('未登录,请先登录')
}
return Promise.reject(response.data.data || 'Error')
} else {
return response
}
},
(error) => {
console.log('err' + error)
// showToast(error.message)
return Promise.reject(error.response.data)
}
)
//导出
export default function useAxiosApi(url, config) {
//console.log(url, config)
return useAxios(url, config, instance)
}
-
加上多接口域名返回和接口检查以及解密
//useAxiosApi.ts
import { useAxios } from '@vueuse/integrations/useAxios' // 导入VueUse库中的useAxios函数
import { Decrypt, isBase64 } from './secret' //解密
import axios from 'axios' // 导入Axios库
import { showToast } from 'vant'
import { useTokenStore } from '@/stores/token'
import { useIsLoggedStore } from '@/stores/isLogged'
//创建一个新的Axios实例
const mainDomainInstance = axios.create({
baseURL: 'http://19.142.34.1:3000/', // 把这个替换成你的主域名
timeout: 10000 // 请求超时时间,默认为10秒
})
// 存储多个域名
let allUrls = []
//选中的接口域名
let selectedUrl = ''
// 使用新的Axios实例请求主域名,获得多个域名
async function getServerUrls() {
const { data: urls } = await mainDomainInstance.get('/api/v1/domain/list')
//需要单独解密
allUrls = JSON.parse(Decrypt(urls)).data
}
//域名检测
async function checkServers() {
if (allUrls.length > 0) {
for (const url of allUrls) {
try {
const response = await mainDomainInstance.get(url.domain + '/api/v1/banners')
if (response.status === 200) {
selectedUrl = url.domain // 如果服务器可用,设置为选中
break // 停止循环,不再检查剩余服务器
}
} catch (err) {
// 如果服务器不可用,打印错误并继续循环
console.error(`Error checking server `, err)
}
}
}
}
//放到一个方法里面,统一调用
async function setup() {
await getServerUrls()
await checkServers()
}
async function createInstance() {
await setup() // 确保setup函数执行完成
//创建一个Axios实例
const instance = axios.create({
baseURL: selectedUrl, // 使用到的接口域名
withCredentials: false, // 是否携带凭证,默认为false
timeout: 10000 // 请求超时时间,默认为5秒
})
instance.defaults.headers.common['Access-Control-Allow-Origin'] = '*'
//添加请求拦截器
instance.interceptors.request.use(
(config) => {
const tokenStore = useTokenStore()
const x_token = tokenStore.x_token
const isLoggedStore = useIsLoggedStore()
if (!x_token) {
isLoggedStore.logoutState()
}
if (x_token) {
config.headers = {
...config.headers,
Authorization: `Bearer ${x_token}`
}
}
return config
},
(error) => {
// 请求错误的处理逻辑
return Promise.reject(error)
}
)
instance.interceptors.response.use(
(response) => {
//检测接口是否是被加密的
// console.log('123456', isBase64(response.data))
if (isBase64(response.data)) {
if (response.status !== 200 && response.status !== 201) {
// 401: Token过期;
if (response.status === 401) {
//返回登录页面
showToast('未登录,请先登录')
}
return Promise.reject(JSON.parse(Decrypt(response.data)) || 'Error')
} else {
response.data = JSON.parse(Decrypt(response.data))
return response
}
} else {
//未被加密的
if (response.status !== 200 && response.status !== 201) {
// 401: Token过期;
if (response.status === 401) {
//返回登录页面
showToast('未登录,请先登录')
}
return Promise.reject(response.data.data || 'Error')
} else {
return response
}
}
},
(error) => {
console.log('err' + error)
if (isBase64(error.response.data)) {
error.response.data = JSON.parse(Decrypt(error.response.data))
return Promise.reject(error.response.data)
} else {
return Promise.reject(error.response.data)
}
}
)
return instance
}
//导出
export default async function useAxiosApi(url, config) {
//console.log(url, config)
const instance = await createInstance()
return useAxios(url, config, instance)
}
-
secret.ts 文件
import CryptoJS from 'crypto-js/crypto-js'
const key = CryptoJS.enc.Utf8.parse('4643647') // 密钥
const iv = CryptoJS.enc.Utf8.parse('437457') // 偏移量
/**
* AES 解密 :字符串 key iv 返回base64
* */
export function Decrypt(word) {
const base64 = CryptoJS.enc.Base64.parse(word)
const src = CryptoJS.enc.Base64.stringify(base64)
const decrypt = CryptoJS.AES.decrypt(src, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return CryptoJS.enc.Utf8.stringify(decrypt)
}
/**
* AES加密 :字符串 key iv 返回base64
*/
export function Encrypt(word) {
const srcs = CryptoJS.enc.Utf8.parse(word)
const encrypted = CryptoJS.AES.encrypt(srcs, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
})
return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
}
//判断是否已经加密
export function isBase64(str) {
const base64Regex =
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$/
return base64Regex.test(str)
}
-
发现的问题
我们发现每次请求的时候,都会去检查域名,我们的要求是:只需要进入页面的时候请求一次接口检测,不需要每次请求都触发接口检测。
-
解决方法
可以在模块级别执行setup
函数。这样,当模块首次加载时,setup
会执行一次,而之后的请求就不会再触发它。由于模块只会加载一次,所以setup
也只会执行一次。为此,需要使用.then
链将Axios实例的创建延迟到setup
执行完成之后。createInstance
函数不再需要等待setup
,因为当instance
被创建时,setup
已经完成了。
-
最终代码
//useAxiosApi.ts
import { useAxios } from '@vueuse/integrations/useAxios'
import { Decrypt, isBase64 } from './secret'
import axios from 'axios'
import { showToast } from 'vant'
import { useTokenStore } from '@/stores/token'
import { useIsLoggedStore } from '@/stores/isLogged'
let allUrls = []
let selectedUrl = ''
let serverCheckedInstance = null
const mainDomainInstance = axios.create({
baseURL: 'http://19xx.143.24.1:3000/',
timeout: 10000
})
async function getServerUrls() {
const { data: urls } = await mainDomainInstance.get('/api/v1/domain/list')
allUrls = JSON.parse(Decrypt(urls)).data
}
async function checkServers() {
if (allUrls.length > 0) {
for (const url of allUrls) {
try {
const response = await mainDomainInstance.get(url.domain + '/api/v1/banners')
if (response.status === 200) {
selectedUrl = url.domain
break
}
} catch (err) {
console.error(`Error checking server `, err)
}
}
}
}
const setup = async () => {
await getServerUrls()
await checkServers()
serverCheckedInstance = axios.create({
baseURL: selectedUrl,
withCredentials: false,
timeout: 10000
})
serverCheckedInstance.defaults.headers.common['Access-Control-Allow-Origin'] = '*'
serverCheckedInstance.interceptors.request.use(
(config) => {
const tokenStore = useTokenStore()
const x_token = tokenStore.x_token
const isLoggedStore = useIsLoggedStore()
if (!x_token) {
isLoggedStore.logoutState()
}
if (x_token) {
config.headers = {
...config.headers,
Authorization: `Bearer ${x_token}`
}
}
return config
},
(error) => {
return Promise.reject(error)
}
)
serverCheckedInstance.interceptors.response.use(
(response) => {
if (isBase64(response.data)) {
if (response.status !== 200 && response.status !== 201) {
if (response.status === 401) {
showToast('未登录,请先登录')
}
return Promise.reject(JSON.parse(Decrypt(response.data)) || 'Error')
} else {
response.data = JSON.parse(Decrypt(response.data))
return response
}
} else {
if (response.status !== 200 && response.status !== 201) {
if (response.status === 401) {
showToast('未登录,请先登录')
}
return Promise.reject(response.data.data || 'Error')
} else {
return response
}
}
},
(error) => {
if (isBase64(error.response.data)) {
error.response.data = JSON.parse(Decrypt(error.response.data))
return Promise.reject(error.response.data)
} else {
return Promise.reject(error.response.data)
}
}
)
}
// Start the setup process immediately
setup()
export default async function useAxiosApi(url, config) {
const getInstance = () => {
if (!serverCheckedInstance) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(getInstance())
}, 500)
})
}
return Promise.resolve(serverCheckedInstance)
}
const instance = await getInstance()
return useAxios(url, config, instance)
}
现在,当你的JavaScript模块(即useAxiosApi.ts
)加载时,会立即开始执行setup
函数,该函数将获取接口域名,然后检查其可用性,然后创建一个配置好的Axios实例。稍后,当你需要发起HTTP请求时,useAxiosApi
函数将等待Axios实例创建完成,然后进行请求。这样能确保setup
只执行一次,且所有请求都在正确的接口域名上执行。
原文始发于微信公众号(大前端编程教学):vue3+axios+useAxios多接口域名检测和加解密(AES)网络请求封装
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/288877.html