修復 too many connection 問題

This commit is contained in:
2025-09-21 02:46:16 +08:00
parent a36ab3c98d
commit 808d5bb52c
36 changed files with 5582 additions and 249 deletions

View File

@@ -0,0 +1,231 @@
// =====================================================
// 客戶端連線清理腳本
// =====================================================
export class ClientConnectionCleanup {
private static instance: ClientConnectionCleanup;
private isCleaning = false;
private clientId: string;
private constructor() {
this.clientId = this.generateClientId();
this.setupEventListeners();
}
public static getInstance(): ClientConnectionCleanup {
if (!ClientConnectionCleanup.instance) {
ClientConnectionCleanup.instance = new ClientConnectionCleanup();
}
return ClientConnectionCleanup.instance;
}
// 生成客戶端唯一標識符
private generateClientId(): string {
const timestamp = Date.now();
const random = Math.random().toString(36).substring(2);
return `client_${timestamp}_${random}`;
}
// 設置事件監聽器
private setupEventListeners() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') {
console.log('🖥️ 客戶端連線清理跳過(服務端環境)');
return;
}
// 頁面關閉前清理
window.addEventListener('beforeunload', () => {
this.cleanupOnUnload();
});
// 頁面隱藏時清理
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
this.cleanupOnHidden();
}
});
// 頁面卸載時清理
window.addEventListener('unload', () => {
this.cleanupOnUnload();
});
// 定期清理每5分鐘
setInterval(() => {
this.periodicCleanup();
}, 5 * 60 * 1000);
console.log('🖥️ 客戶端連線清理已啟動');
}
// 頁面關閉前清理
private async cleanupOnUnload() {
if (this.isCleaning) return;
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
this.isCleaning = true;
console.log('🔄 頁面關閉前清理連線...');
try {
// 使用 sendBeacon 確保請求能夠發送
const data = JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
timestamp: Date.now()
});
// 嘗試使用 sendBeacon
if (navigator.sendBeacon) {
navigator.sendBeacon('/api/ip-cleanup', data);
console.log('✅ 使用 sendBeacon 發送清理請求');
} else {
// 備用方案:使用 fetch
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: data,
keepalive: true
});
console.log('✅ 使用 fetch 發送清理請求');
}
} catch (error) {
console.error('❌ 清理請求發送失敗:', error);
}
}
// 頁面隱藏時清理
private async cleanupOnHidden() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
console.log('🔄 頁面隱藏時清理連線...');
try {
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
reason: 'page-hidden'
})
});
console.log('✅ 頁面隱藏清理完成');
} catch (error) {
console.error('❌ 頁面隱藏清理失敗:', error);
}
}
// 定期清理
private async periodicCleanup() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return;
console.log('🔄 定期清理連線...');
try {
const response = await fetch('/api/ip-cleanup?action=local-stats');
const data = await response.json();
if (data.success && data.data.trackedConnections > 10) {
// 如果追蹤的連線數超過10個執行清理
await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-local',
clientId: this.clientId,
reason: 'periodic-cleanup'
})
});
console.log('✅ 定期清理完成');
}
} catch (error) {
console.error('❌ 定期清理失敗:', error);
}
}
// 手動清理
public async manualCleanup(): Promise<boolean> {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return false;
try {
const response = await fetch('/api/ip-cleanup', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
action: 'cleanup-current',
clientId: this.clientId,
reason: 'manual-cleanup'
})
});
const data = await response.json();
if (data.success) {
console.log('✅ 手動清理完成:', data.message);
return true;
} else {
console.error('❌ 手動清理失敗:', data.error);
return false;
}
} catch (error) {
console.error('❌ 手動清理錯誤:', error);
return false;
}
}
// 獲取連線狀態
public async getConnectionStatus() {
// 確保在瀏覽器環境中執行
if (typeof window === 'undefined') return null;
try {
const response = await fetch('/api/ip-cleanup?action=status');
const data = await response.json();
if (data.success) {
console.log('📊 連線狀態:', data.data);
return data.data;
} else {
console.error('❌ 獲取連線狀態失敗:', data.error);
return null;
}
} catch (error) {
console.error('❌ 獲取連線狀態錯誤:', error);
return null;
}
}
// 獲取客戶端 ID
public getClientId(): string {
return this.clientId;
}
}
// 導出單例實例
export const clientCleanup = ClientConnectionCleanup.getInstance();
// 在模組載入時自動初始化(只在瀏覽器環境中)
if (typeof window !== 'undefined') {
// 延遲初始化,確保 DOM 已載入
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
clientCleanup;
});
} else {
clientCleanup;
}
}