diff --git a/package.json b/package.json index 0bd3aa6..138b0db 100644 --- a/package.json +++ b/package.json @@ -11,10 +11,12 @@ }, "dependencies": { "@mdi/font": "7.4.47", + "@microsoft/clarity": "^1.0.0", "axios": "^1.8.4", "idb": "^8.0.2", "js-yaml": "^4.1.0", "pinyin-pro": "^3.26.0", + "ratelimit-header-parser": "^0.1.0", "roboto-fontface": "*", "typewriter-effect": "^2.21.0", "uuid": "^9.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dcb427c..07deb8f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@mdi/font': specifier: 7.4.47 version: 7.4.47 + '@microsoft/clarity': + specifier: ^1.0.0 + version: 1.0.0 axios: specifier: ^1.8.4 version: 1.8.4 @@ -23,6 +26,9 @@ importers: pinyin-pro: specifier: ^3.26.0 version: 3.26.0 + ratelimit-header-parser: + specifier: ^0.1.0 + version: 0.1.0 roboto-fontface: specifier: '*' version: 0.10.0 @@ -939,6 +945,9 @@ packages: '@mdi/font@7.4.47': resolution: {integrity: sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==} + '@microsoft/clarity@1.0.0': + resolution: {integrity: sha512-2QY6SmXnqRj6dWhNY8NYCN3e53j4zCFebH4wGnNhdGV1mqAsQwql2fT0w8TISxCvwwfVp8idsWLIdrRHOms1PQ==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2624,6 +2633,9 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + ratelimit-header-parser@0.1.0: + resolution: {integrity: sha512-+gg0VX4h0nBT5JWZfaPNwAV8pWRZa3MAFHLZNUYO5yqw+4IvU64HmPtA3aRapQ2uSP1x3Ta4TZO0k516dtNLZA==} + react-dom@18.3.1: resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} peerDependencies: @@ -4332,6 +4344,8 @@ snapshots: '@mdi/font@7.4.47': {} + '@microsoft/clarity@1.0.0': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -6175,6 +6189,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + ratelimit-header-parser@0.1.0: {} + react-dom@18.3.1(react@18.3.1): dependencies: loose-envify: 1.4.0 diff --git a/src/App.vue b/src/App.vue index 3c2d0a7..84bf10b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,47 +1,52 @@ +} + diff --git a/src/axios/axios.js b/src/axios/axios.js index 889a94e..cdae19e 100644 --- a/src/axios/axios.js +++ b/src/axios/axios.js @@ -1,6 +1,7 @@ import axios from "axios"; -import { getSetting } from '@/utils/settings'; - +import { getSetting } from "@/utils/settings"; +import { parseRateLimit } from "ratelimit-header-parser"; +import RateLimitModal from "@/components/RateLimitModal.vue"; // 基本配置 const axiosInstance = axios.create({ // 可以在这里添加基础配置,例如超时时间等 @@ -11,7 +12,7 @@ const axiosInstance = axios.create({ axiosInstance.interceptors.request.use( (requestConfig) => { // 确保每次请求时都获取最新的 siteKey - const siteKey = getSetting('server.siteKey'); + const siteKey = getSetting("server.siteKey"); if (siteKey) { requestConfig.headers["x-site-key"] = siteKey; } @@ -23,4 +24,33 @@ axiosInstance.interceptors.request.use( } ); +// 响应拦截器 +axiosInstance.interceptors.response.use( + (response) => { + return response; + }, + (error) => { + // 处理限速响应 (HTTP 429) + if (error.response && error.response.status === 429) { + try { + // 解析限速头信息 + const rateLimitInfo = parseRateLimit(error.response); + + if (rateLimitInfo) { + // 显示限速弹窗,直接传递重置时间 + RateLimitModal.show( + rateLimitInfo.reset, + error.config.url, + error.config.method.toUpperCase() + ); + } + } catch (parseError) { + console.error("解析限速头信息失败:", parseError); + } + } + + return Promise.reject(error); + } +); + export default axiosInstance; diff --git a/src/components/RateLimitModal.vue b/src/components/RateLimitModal.vue new file mode 100644 index 0000000..9f2877d --- /dev/null +++ b/src/components/RateLimitModal.vue @@ -0,0 +1,143 @@ + + + diff --git a/src/main.js b/src/main.js index 2a4030f..309bf24 100644 --- a/src/main.js +++ b/src/main.js @@ -13,7 +13,10 @@ import GlobalMessage from '@/components/GlobalMessage.vue' // Composables import { createApp } from 'vue' +import Clarity from '@microsoft/clarity'; +const projectId = "rhp8uqoc3l" +Clarity.init(projectId); import messageService from './utils/message'; const app = createApp(App)