瀏覽代碼

前端新增本地缓存,过期1小时

mrh 1 年之前
父節點
當前提交
c5ad8ffd34

+ 0 - 4
ui/backend/config.yaml

@@ -17,10 +17,6 @@ sub:
       file_path: g:\code\upwork\zhang_crawl_bio\download\proxy_pool\temp\9664.yaml
       name: "\U0001F1EF\U0001F1F5\u65E5\u672C\u4E13\u7EBF4"
       port: 9664
-    9666:
-      file_path: g:\code\upwork\zhang_crawl_bio\download\proxy_pool\temp\9666.yaml
-      name: "\U0001F1EF\U0001F1F5\u4E9A\u9A6C\u900A\u65E5\u672C2"
-      port: 9666
   start_port: 9660
   temp_dir: g:\code\upwork\zhang_crawl_bio\download\proxy_pool\temp
   url: https://www.yfjc.xyz/api/v1/client/subscribe?token=b74f2207492053926f7511a8e474048f

+ 1 - 1
ui/backend/utils/config.py

@@ -36,7 +36,7 @@ class Config(BaseModel):
     def save(self):
         config_path = get_config_path()
         with open(config_path, "w", encoding="utf-8") as file:
-            yaml.dump(self.model_dump(), file)
+            yaml.dump(self.model_dump(), file, encoding="utf-8", )
         return self
             
 def get_config_path():

+ 8 - 0
ui/docs/gpt/vue_cache.md

@@ -0,0 +1,8 @@
+G:\code\upwork\zhang_crawl_bio\ui 当前项目采用 vue3(语法糖) + element-plus + fastapi 架构。
+由于 proxy.py 是 /api/proxy/{router} 的接口 ,当前端请求时,有些接口需要耗时5s~15s
+我想在前端层面首次启动时,就调用 get_sub_url get_sys_proxy 接口,并且记录时间戳存储到本地作为缓存。
+因此前端可能要封装这两个请求让它支持缓存的操作,避免频繁长时间请求,让 UI 切换更加顺滑。
+
+同时,缓存也会过期,因此或许可以设置一个代理守卫,定期获取数据,自动保存到前端本地。这样缓存就会一直保持最新,并且让用户无感体验。
+
+我这个思路是否符合前后端最佳软件设计架构?你来决定应该如何优化。

+ 3 - 0
ui/fontend/src/components/Home.vue

@@ -12,4 +12,7 @@
 <script setup lang="ts">
 import { useProxyStore } from '../stores/proxyStore'
 const store = useProxyStore()
+console.log(store.selectedProxy);
+console.log(store.proxyData);
+
 </script>

+ 10 - 12
ui/fontend/src/components/Proxy.vue

@@ -41,29 +41,27 @@ const sys_proxy = ref<{sys_open: boolean, proxy_server: string}>({
 })
 const subUrl = ref('')
 
-// 获取订阅链接
+// 获取订阅链接(带缓存)
 const get_sub_url = async () => {
   try {
-    const response = await fetch(apiBaseUrl + '/proxy/subs')
-    if (!response.ok) throw new Error('获取订阅链接失败')
-    const data = await response.json()
+    const cacheKey = 'sub_url_cache'
+    const data = await store.cachedFetch(`${apiBaseUrl}/proxy/subs`, cacheKey)
     subUrl.value = data.msg?.url || ''
-    console.log("get_sub_url: ", data.msg);
-    
   } catch (error) {
-    console.error(error)
+    console.error('获取订阅链接失败:', error)
+    ElMessage.error('获取订阅信息失败')
   }
 }
 
-// 获取系统代理信息
+// 获取系统代理信息(带缓存)
 const get_sys_proxy = async () => {
   try {
-    const response = await fetch(apiBaseUrl + '/proxy/sys')
-    if (!response.ok) throw new Error('获取代理信息失败')
-    const data = await response.json()
+    const cacheKey = 'sys_proxy_cache'
+    const data = await store.cachedFetch(`${apiBaseUrl}/proxy/sys`, cacheKey)
     sys_proxy.value = data
+    store.setProxyData(data) // 保持store数据同步
   } catch (error) {
-    console.error(error)
+    console.error('获取代理信息失败:', error)
     ElMessage.error('获取代理信息失败')
   }
 }

+ 18 - 6
ui/fontend/src/components/ProxyPool.vue

@@ -8,7 +8,7 @@
       <el-table :data="proxyList" border stripe v-loading="loading">
         <el-table-column prop="name" label="代理名称" width="100" />
         <el-table-column prop="port" label="端口" width="100" align="center" />
-        <el-table-column label="状态" width="120" align="center">
+        <el-table-column label="状态" width="80" align="center">
           <template #default="{ row }">
             <el-tag
               :type="row.reachable ? 'success' : 'danger'"
@@ -19,7 +19,7 @@
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="管理地址">
+        <el-table-column label="管理地址" width="90">
           <template #default="{ row }">
             <el-link v-if="row.reachable && row.mgr_url" :href="row.mgr_url || ''" target="_blank">
                 <el-icon><Link /></el-icon>访问
@@ -74,6 +74,9 @@
 <script setup lang="ts">
 import { ref } from 'vue'
 import type { ProxyResponse, ProxyPostResponse } from '../api-types'
+import { useProxyStore } from '../stores/proxyStore'
+import { log } from 'console'
+const store = useProxyStore()
 
 const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || ''
 const proxyList = ref<ProxyResponse[]>([])
@@ -82,13 +85,22 @@ const creating = ref(false)
 const detailVisible = ref(false)
 const selectedProxy = ref<ProxyResponse | null>(null)
 
-const fetchProxyList = async () => {
+const fetchProxyList = async (useCatch=true) => {
 try {
     loading.value = true
-    const response = await fetch(`${apiBaseUrl}/proxy/proxies`)
-    if (!response.ok) throw new Error('获取代理列表失败')
+    let response:Response
+    let data: ProxyResponse[]
+    if (useCatch) {
+      const cacheKey = 'fetchProxyList'
+      data = await store.cachedFetch(`${apiBaseUrl}/proxy/proxies`, cacheKey)
+      console.log(`useCatch ${cacheKey}: `, data)
+    }
+    else {
+      response = await fetch(`${apiBaseUrl}/proxy/proxies`)
+      if (!response.ok) throw new Error('获取代理列表失败')
+      data = await response.json()
+    }
     
-    const data = await response.json()
     proxyList.value = data.map((proxy: ProxyResponse) => ({
       ...proxy,
       isLoading: proxy.isLoading || false

+ 52 - 1
ui/fontend/src/stores/proxyStore.ts

@@ -1,10 +1,50 @@
 import { defineStore } from 'pinia'
 import { ref } from 'vue'
 
+// 缓存配置
+const CACHE_TTL = 3600000 // 1小时缓存有效期
+
+interface CacheItem {
+  timestamp: number
+  data: any
+}
+
 export const useProxyStore = defineStore('proxy', () => {
   const selectedProxy = ref(localStorage.getItem('selectedProxy') || 'system')
   const proxyData = ref(JSON.parse(localStorage.getItem('proxyData') || '{}'))
 
+  // 带缓存的请求方法
+  async function cachedFetch(url: string, cacheKey: string) {
+    const now = Date.now()
+    
+    // 尝试从缓存读取
+    const cached = localStorage.getItem(cacheKey)
+    if (cached) {
+      try {
+        const { timestamp, data }: CacheItem = JSON.parse(cached)
+        if (now - timestamp < CACHE_TTL) {
+          return data
+        }
+      } catch (e) {
+        console.warn('Invalid cache format', e)
+      }
+    }
+
+    // 发起新请求
+    const response = await fetch(url)
+    if (!response.ok) throw new Error(`Request failed: ${response.status}`)
+    const data = await response.json()
+    
+    // 更新缓存
+    const cacheItem: CacheItem = {
+      timestamp: now,
+      data
+    }
+    localStorage.setItem(cacheKey, JSON.stringify(cacheItem))
+    
+    return data
+  }
+
   function setSelectedProxy(choice: string) {
     selectedProxy.value = choice
     localStorage.setItem('selectedProxy', choice)
@@ -13,7 +53,18 @@ export const useProxyStore = defineStore('proxy', () => {
   function setProxyData(data: any) {
     proxyData.value = data
     localStorage.setItem('proxyData', JSON.stringify(data))
+    // 同时更新系统代理缓存
+    localStorage.setItem('sys_proxy_cache', JSON.stringify({
+      timestamp: Date.now(),
+      data
+    }))
   }
 
-  return { selectedProxy, proxyData, setSelectedProxy, setProxyData }
+  return { 
+    selectedProxy, 
+    proxyData, 
+    setSelectedProxy, 
+    setProxyData,
+    cachedFetch 
+  }
 })