feat: webAddress
This commit is contained in:
@@ -1,92 +0,0 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
export const useWebsiteTitle = () => {
|
||||
const titles = ref<Map<string, string>>(new Map())
|
||||
const loading = ref(new Set<string>())
|
||||
const errors = ref(new Map<string, string>())
|
||||
|
||||
// 新增:重试配置
|
||||
const MAX_RETRY = 3
|
||||
const BASE_DELAY = 800 // 毫秒
|
||||
|
||||
const getCache = (url: string) => {
|
||||
const cached = sessionStorage.getItem(`title_cache_${url}`)
|
||||
if (!cached) return null
|
||||
const { title, expire } = JSON.parse(cached)
|
||||
return Date.now() < expire ? title : null
|
||||
}
|
||||
|
||||
const setCache = (url: string, title: string) => {
|
||||
const data = { title, expire: Date.now() + 7 * 24 * 60 * 60 * 1000 }
|
||||
sessionStorage.setItem(`title_cache_${url}`, JSON.stringify(data))
|
||||
}
|
||||
|
||||
const fetchWithRetry = async (url: string, retryCount = 0): Promise<string> => {
|
||||
const proxyUrl = `https://api.allorigins.win/raw?url=${encodeURIComponent(url)}`
|
||||
|
||||
try {
|
||||
const res = await fetch(proxyUrl)
|
||||
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP ${res.status}`)
|
||||
}
|
||||
|
||||
const html = await res.text()
|
||||
const parser = new DOMParser()
|
||||
const doc = parser.parseFromString(html, 'text/html')
|
||||
const title =
|
||||
doc.querySelector('title')?.textContent?.trim() || new URL(url).hostname || '无标题'
|
||||
|
||||
return title
|
||||
} catch (err) {
|
||||
if (retryCount >= MAX_RETRY) {
|
||||
throw err // 达到最大重试次数,抛出错误
|
||||
}
|
||||
|
||||
// 第1次等800ms,第2次等1600ms,第3次等3200ms
|
||||
const delay = BASE_DELAY * Math.pow(2, retryCount)
|
||||
console.warn(
|
||||
`获取标题失败,${retryCount + 1}/${MAX_RETRY} 次重试,等待 ${delay}ms`,
|
||||
url
|
||||
)
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, delay))
|
||||
return fetchWithRetry(url, retryCount + 1)
|
||||
}
|
||||
}
|
||||
|
||||
const fetchTitle = async (url: string): Promise<string> => {
|
||||
if (titles.value.has(url)) return titles.value.get(url)!
|
||||
|
||||
const cached = getCache(url)
|
||||
if (cached) {
|
||||
titles.value.set(url, cached)
|
||||
return cached
|
||||
}
|
||||
|
||||
if (loading.value.has(url)) return ''
|
||||
|
||||
loading.value.add(url)
|
||||
errors.value.delete(url)
|
||||
|
||||
try {
|
||||
const title = await fetchWithRetry(url)
|
||||
titles.value.set(url, title)
|
||||
setCache(url, title)
|
||||
return title
|
||||
} catch (err) {
|
||||
const msg = `获取标题失败(已重试 ${MAX_RETRY} 次)`
|
||||
errors.value.set(url, msg)
|
||||
console.error(err)
|
||||
return msg
|
||||
} finally {
|
||||
loading.value.delete(url)
|
||||
}
|
||||
}
|
||||
|
||||
const fetchAll = async (urls: string[]) => {
|
||||
await Promise.allSettled(urls.map(fetchTitle))
|
||||
}
|
||||
|
||||
return { titles, loading, errors, fetchTitle, fetchAll }
|
||||
}
|
||||
Reference in New Issue
Block a user