Appearance
起因
最近想给博客的友链添加一个自动监测功能,能够显示每个友链的在线状态。这样访问者就能知道哪些朋友的网站还能正常访问
实现过程
1. 定义类型接口
首先创建类型定义文件 types/linkStatus.ts:
typescript
export interface FriendLink {
name: string
title: string
avatar: string
link: string
status?: LinkStatus
lastChecked?: Date
}
export interface LinkStatus {
isOnline: boolean
statusCode?: number
responseTime?: number
error?: string
}2. 实现链接检查服务
创建 utils/simpleLinkChecker.ts:
typescript
export class SimpleLinkChecker {
async checkLinks(links: FriendLink[]): Promise<FriendLink[]> {
const results = await Promise.allSettled(links.map((link) => this.checkSingleLink(link)))
return links.map((link, index) => {
const result = results[index]
if (result.status === 'fulfilled' && result.value) {
return {
...link,
status: result.value.status,
lastChecked: result.value.timestamp
}
}
// If failed, mark as offline
return {
...link,
status: {
isOnline: false,
error: result.status === 'rejected' ? result.reason.message : 'Check failed'
},
lastChecked: new Date()
}
})
}
}遇到的坑
CORS 问题
第一个大坑是浏览器的 CORS 政策。最初我尝试直接发送 HEAD 请求:
typescript
const response = await fetch(link.link, {
method: 'HEAD',
mode: 'cors'
})但大多数网站都不会返回 CORS 头,导致请求失败。解决方案是:
- 先尝试
mode: 'cors' - 如果失败,改用
mode: 'no-cors' - 作为后备,使用
Image对象加载
typescript
// Try with ping approach using Image
const img = new Image()
await new Promise((resolve, reject) => {
img.onload = resolve
img.onerror = () => reject(new Error('Image load failed'))
img.src = link.link + '?t=' + Date.now()
})Vue 列表渲染问题
在实现排序功能时,遇到了一个奇怪的问题:排序后不同的友链显示了相同的头像。这是因为 Vue 的虚拟 DOM 复用机制
问题代码:
vue
<div v-for="(friend, index) in displayLinks" :key="index"></div>解决方案:
vue
<div v-for="(friend, index) in displayLinks" :key="friend.link"></div>使用 friend.link 作为 key,确保每个元素都有唯一的标识
缓存策略
为了避免每次页面加载都检查所有链接,实现了缓存机制:
typescript
// Save to localStorage
localStorage.setItem(
'friendLinksStatus',
JSON.stringify({
links: results,
timestamp: Date.now()
})
)
// Check if cache is expired (24 hours)
const hoursSinceLastCheck = (now - lastCheck) / (1000 * 60 * 60)
if (hoursSinceLastCheck >= 24) {
this.checkLinksStatus()
}最终效果
- 自动排序:在线的友链自动排在前面
- 状态显示:右上角显示 "ONLINE" 或 "OFFLINE" 标签
- 每日更新:每 24 小时自动检查一次
- 本地缓存:使用 localStorage 缓存结果