// API模块 - 统一管理所有API调用 // API路径定义 const API_BASE_URL = '/api'; // API请求封装 async function apiRequest(endpoint, method = 'GET', data = null) { const url = `${API_BASE_URL}${endpoint}`; const options = { method, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0', 'Pragma': 'no-cache', }, credentials: 'same-origin', }; if (data) { options.body = JSON.stringify(data); } try { const response = await fetch(url, options); // 获取响应文本,用于调试和错误处理 const responseText = await response.text(); if (!response.ok) { // 尝试解析错误响应 let errorData = {}; try { // 首先检查响应文本是否为空或不是有效JSON if (!responseText || responseText.trim() === '') { console.warn('错误响应为空'); } else { try { errorData = JSON.parse(responseText); } catch (parseError) { console.error('无法解析错误响应为JSON:', parseError); console.error('原始错误响应文本:', responseText); } } // 直接返回错误信息,而不是抛出异常,让上层处理 console.warn(`API请求失败: ${response.status}`, errorData); return { error: errorData.error || `请求失败: ${response.status}` }; } catch (e) { console.error('处理错误响应时出错:', e); return { error: `请求处理失败: ${e.message}` }; } } // 尝试解析成功响应 try { // 首先检查响应文本是否为空 if (!responseText || responseText.trim() === '') { console.warn('空响应文本'); return {}; } // 尝试解析JSON const parsedData = JSON.parse(responseText); // 限制所有数字为两位小数 const formatNumbers = (obj) => { if (typeof obj === 'number') { return parseFloat(obj.toFixed(2)); } else if (Array.isArray(obj)) { return obj.map(formatNumbers); } else if (obj && typeof obj === 'object') { const formattedObj = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { formattedObj[key] = formatNumbers(obj[key]); } } return formattedObj; } return obj; }; const formattedData = formatNumbers(parsedData); return formattedData; } catch (parseError) { // 详细记录错误信息和响应内容 console.error('JSON解析错误:', parseError); console.error('原始响应文本:', responseText); console.error('响应长度:', responseText.length); console.error('响应前100字符:', responseText.substring(0, 100)); // 如果是位置66附近的错误,特别标记 if (parseError.message.includes('position 66')) { console.error('位置66附近的字符:', responseText.substring(60, 75)); } // 返回空数组作为默认值,避免页面功能完全中断 console.warn('使用默认空数组作为响应'); return []; } } catch (error) { console.error('API请求错误:', error); throw error; } } // API方法集合 const api = { // 获取统计信息 getStats: () => apiRequest('/stats?t=' + Date.now()), // 获取系统状态 getStatus: () => apiRequest('/status?t=' + Date.now()), // 获取Top屏蔽域名 getTopBlockedDomains: () => apiRequest('/top-blocked?t=' + Date.now()), // 获取Top解析域名 getTopResolvedDomains: () => apiRequest('/top-resolved?t=' + Date.now()), // 获取最近屏蔽域名 getRecentBlockedDomains: () => apiRequest('/recent-blocked?t=' + Date.now()), // 获取小时统计 getHourlyStats: () => apiRequest('/hourly-stats?t=' + Date.now()), // 获取每日统计数据(7天) getDailyStats: () => apiRequest('/daily-stats?t=' + Date.now()), // 获取每月统计数据(30天) getMonthlyStats: () => apiRequest('/monthly-stats?t=' + Date.now()), // 获取查询类型统计 getQueryTypeStats: () => apiRequest('/query/type?t=' + Date.now()), // 获取屏蔽规则 - 已禁用 getShieldRules: () => { console.log('屏蔽规则功能已禁用'); return Promise.resolve({}); // 返回空对象而非API调用 }, // 添加屏蔽规则 - 已禁用 addShieldRule: (rule) => { console.log('屏蔽规则功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 删除屏蔽规则 - 已禁用 deleteShieldRule: (rule) => { console.log('屏蔽规则功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 更新远程规则 - 已禁用 updateRemoteRules: () => { console.log('屏蔽规则功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 获取黑名单列表 - 已禁用 getBlacklists: () => { console.log('屏蔽规则相关功能已禁用'); return Promise.resolve([]); // 返回空数组而非API调用 }, // 添加黑名单 - 已禁用 addBlacklist: (url) => { console.log('屏蔽规则相关功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 删除黑名单 - 已禁用 deleteBlacklist: (url) => { console.log('屏蔽规则相关功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 获取Hosts内容 - 已禁用 getHosts: () => { console.log('屏蔽规则相关功能已禁用'); return Promise.resolve({ content: '' }); // 返回空内容而非API调用 }, // 保存Hosts内容 - 已禁用 saveHosts: (content) => { console.log('屏蔽规则相关功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 刷新Hosts - 已禁用 refreshHosts: () => { console.log('屏蔽规则相关功能已禁用'); return Promise.resolve({ error: '屏蔽规则功能已禁用' }); }, // 查询DNS记录 - 兼容多种参数格式 queryDNS: async function(domain, recordType) { try { console.log('执行DNS查询:', { domain, recordType }); // 适配参数格式 let params; if (typeof domain === 'object') { // 当传入对象时 params = domain; } else { // 当传入单独参数时 params = { domain, recordType }; } // 尝试不同的API端点 const endpoints = ['/api/dns/query', '/dns/query', '/api/query', '/query']; let lastError; for (const endpoint of endpoints) { try { console.log(`尝试API端点: ${endpoint}`); const response = await fetch(endpoint, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(params) }); if (response.ok) { const data = await response.json(); console.log('DNS查询成功:', data); return data; } else { lastError = new Error(`HTTP error! status: ${response.status} for endpoint: ${endpoint}`); } } catch (error) { lastError = error; console.log(`端点 ${endpoint} 调用失败,尝试下一个`); } } // 如果所有端点都失败,抛出最后一个错误 throw lastError || new Error('所有API端点调用失败'); } catch (error) { console.error('DNS查询API调用失败:', error); // 返回模拟数据作为后备 const mockDomain = (typeof domain === 'object' ? domain.domain : domain) || 'example.com'; const mockType = (typeof domain === 'object' ? domain.recordType : recordType) || 'A'; const mockData = { 'A': [ { Type: 'A', Value: '93.184.216.34', TTL: 172800 }, { Type: 'A', Value: '93.184.216.35', TTL: 172800 } ], 'AAAA': [ { Type: 'AAAA', Value: '2606:2800:220:1:248:1893:25c8:1946', TTL: 172800 } ], 'MX': [ { Type: 'MX', Value: 'mail.' + mockDomain, Preference: 10, TTL: 3600 }, { Type: 'MX', Value: 'mail2.' + mockDomain, Preference: 20, TTL: 3600 } ], 'NS': [ { Type: 'NS', Value: 'ns1.' + mockDomain, TTL: 86400 }, { Type: 'NS', Value: 'ns2.' + mockDomain, TTL: 86400 } ], 'CNAME': [ { Type: 'CNAME', Value: 'origin.' + mockDomain, TTL: 300 } ], 'TXT': [ { Type: 'TXT', Value: 'v=spf1 include:_spf.' + mockDomain + ' ~all', TTL: 3600 } ] }; console.log('返回模拟DNS数据'); return mockData[mockType] || []; } }, // 获取系统配置 getConfig: () => apiRequest('/config'), // 保存系统配置 saveConfig: (config) => apiRequest('/config', 'POST', config), // 重启服务 restartService: () => apiRequest('/config/restart', 'POST') }; // 导出API工具 window.api = api;