diff --git a/http/server.go b/http/server.go index 15e2839..5987540 100644 --- a/http/server.go +++ b/http/server.go @@ -42,6 +42,7 @@ func (s *Server) Start() error { mux.HandleFunc("/api/stats", s.handleStats) mux.HandleFunc("/api/shield", s.handleShield) mux.HandleFunc("/api/shield/hosts", s.handleShieldHosts) + mux.HandleFunc("/api/shield/blacklists", s.handleShieldBlacklists) mux.HandleFunc("/api/query", s.handleQuery) mux.HandleFunc("/api/status", s.handleStatus) mux.HandleFunc("/api/config", s.handleConfig) @@ -194,14 +195,21 @@ func (s *Server) handleHourlyStats(w http.ResponseWriter, r *http.Request) { func (s *Server) handleShield(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") - // 处理hosts管理子路由 - if strings.HasPrefix(r.URL.Path, "/api/shield/hosts") { - s.handleShieldHosts(w, r) - return + // 返回屏蔽规则的基本配置信息 + switch r.Method { + case http.MethodGet: + shieldInfo := map[string]interface{}{ + "updateInterval": s.globalConfig.Shield.UpdateInterval, + "blockMethod": s.globalConfig.Shield.BlockMethod, + "blacklistCount": len(s.globalConfig.Shield.Blacklists), + } + json.NewEncoder(w).Encode(shieldInfo) + default: + http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } // 处理远程黑名单管理子路由 - if strings.HasPrefix(r.URL.Path, "/api/shield/blacklists") { + if strings.HasPrefix(r.URL.Path, "/shield/blacklists") { s.handleShieldBlacklists(w, r) return } @@ -268,21 +276,26 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) // 处理更新单个黑名单 if strings.Contains(r.URL.Path, "/update") { if r.Method == http.MethodPost { - // 提取黑名单ID + // 提取黑名单URL或Name parts := strings.Split(r.URL.Path, "/") - var id string + var targetURLOrName string for i, part := range parts { if part == "blacklists" && i+1 < len(parts) && parts[i+1] != "update" { - id = parts[i+1] + targetURLOrName = parts[i+1] break } } + if targetURLOrName == "" { + http.Error(w, "黑名单标识不能为空", http.StatusBadRequest) + return + } + // 获取黑名单列表 blacklists := s.shieldManager.GetBlacklists() var targetIndex = -1 for i, list := range blacklists { - if list.URL == id || list.Name == id { + if list.URL == targetURLOrName || list.Name == targetURLOrName { targetIndex = i break } @@ -293,18 +306,13 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) return } - // 尝试更新该黑名单 - if err := s.shieldManager.fetchRemoteRules(blacklists[targetIndex].URL); err != nil { - // 更新失败,但不返回错误,而是更新状态 - blacklists[targetIndex].LastUpdateTime = time.Now().Format(time.RFC3339) - } else { - // 更新成功 - blacklists[targetIndex].LastUpdateTime = time.Now().Format(time.RFC3339) - // 重新加载规则 - s.shieldManager.LoadRules() - } - + // 更新时间戳 + blacklists[targetIndex].LastUpdateTime = time.Now().Format(time.RFC3339) + // 保存更新后的黑名单列表 s.shieldManager.UpdateBlacklist(blacklists) + // 重新加载规则以获取最新的远程规则 + s.shieldManager.LoadRules() + json.NewEncoder(w).Encode(map[string]string{"status": "success"}) return } @@ -372,8 +380,7 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) blacklists = append(blacklists, newEntry) s.shieldManager.UpdateBlacklist(blacklists) - // 尝试获取规则 - s.shieldManager.fetchRemoteRules(req.URL) + // 重新加载规则以获取新添加的远程规则 s.shieldManager.LoadRules() json.NewEncoder(w).Encode(map[string]string{"status": "success"}) @@ -382,8 +389,7 @@ func (s *Server) handleShieldBlacklists(w http.ResponseWriter, r *http.Request) // 更新所有远程黑名单 blacklists := s.shieldManager.GetBlacklists() for i := range blacklists { - // 尝试更新每个黑名单 - s.shieldManager.fetchRemoteRules(blacklists[i].URL) + // 更新每个黑名单的时间戳 blacklists[i].LastUpdateTime = time.Now().Format(time.RFC3339) } diff --git a/static/js/app.js b/static/js/app.js index 922e9fa..a807cc9 100644 --- a/static/js/app.js +++ b/static/js/app.js @@ -1,5 +1,5 @@ // 全局配置 -const API_BASE_URL = '/api'; +const API_BASE_URL = '.'; // DOM 加载完成后执行 document.addEventListener('DOMContentLoaded', function() { @@ -65,7 +65,7 @@ if (typeof window.showNotification === 'undefined') { // 加载初始数据(主要用于服务器状态) function loadInitialData() { // 加载服务器状态 - fetch(`${API_BASE_URL}/status`) + fetch(`${API_BASE_URL}/api/status`) .then(response => response.json()) .then(data => { // 更新服务器状态指示器 diff --git a/static/js/modules/blacklists.js b/static/js/modules/blacklists.js index f22785c..03ac8d7 100644 --- a/static/js/modules/blacklists.js +++ b/static/js/modules/blacklists.js @@ -28,7 +28,7 @@ function loadBlacklists() { const tbody = document.getElementById('blacklists-table').querySelector('tbody'); showLoading(tbody); - apiRequest('/shield') + apiRequest('/api/shield/blacklists') .then(data => { renderBlacklists(data); }) @@ -123,9 +123,9 @@ function addBlacklist() { return; } - apiRequest('/shield', 'POST', { name: name, url: url }) + apiRequest('/api/shield/blacklists', 'POST', { name: name, url: url }) .then(data => { - if (data.success) { + if (data.status === 'success') { window.showNotification('远程黑名单添加成功', 'success'); nameInput.value = ''; urlInput.value = ''; @@ -142,9 +142,9 @@ function addBlacklist() { // 更新远程黑名单 function updateBlacklist(id) { - apiRequest(`/shield/${id}/update`, 'POST') + apiRequest(`/api/shield/blacklists/${id}/update`, 'POST') .then(data => { - if (data.success) { + if (data.status === 'success') { window.showNotification('远程黑名单更新成功', 'success'); loadBlacklists(); } else { @@ -162,9 +162,9 @@ function updateAllBlacklists() { confirmAction( '确定要更新所有远程黑名单吗?这可能需要一些时间。', () => { - apiRequest('/shield/update-all', 'POST') + apiRequest('/api/shield/blacklists', 'PUT') .then(data => { - if (data.success) { + if (data.status === 'success') { window.showNotification('所有远程黑名单更新成功', 'success'); loadBlacklists(); } else { @@ -181,9 +181,9 @@ function updateAllBlacklists() { // 删除远程黑名单 function deleteBlacklist(id) { - apiRequest(`/shield/${id}`, 'DELETE') + apiRequest(`/api/shield/blacklists/${id}`, 'DELETE') .then(data => { - if (data.success) { + if (data.status === 'success') { window.showNotification('远程黑名单删除成功', 'success'); loadBlacklists(); } else { diff --git a/static/js/modules/dashboard.js b/static/js/modules/dashboard.js index f8aa30c..5a15e09 100644 --- a/static/js/modules/dashboard.js +++ b/static/js/modules/dashboard.js @@ -191,7 +191,7 @@ function updateDomainRankings() { // 更新统计卡片数据 function updateStatCards() { // 获取所有统计数据 - apiRequest('/stats') + apiRequest('/api/stats') .then(data => { // 更新请求统计 if (data && data.dns) { @@ -239,7 +239,7 @@ function updateStatCards() { }); // 获取规则数 - apiRequest('/shield') + apiRequest('/api/shield') .then(data => { let rulesCount = 0; @@ -285,7 +285,7 @@ function updateStatCards() { }); // 获取Hosts条目数量 - apiRequest('/shield/hosts') + apiRequest('/api/shield/hosts') .then(data => { let hostsCount = 0; @@ -318,7 +318,7 @@ function updateStatCards() { }); // 获取Hosts条目数 - apiRequest('/shield/hosts') + apiRequest('/api/shield/hosts') .then(data => { let hostsCount = 0; if (Array.isArray(data)) { @@ -834,7 +834,7 @@ function loadTopBlockedDomains(isUpdate = false) { tbody.innerHTML = `加载中...`; } - return apiRequest('/top-blocked') + return apiRequest('/api/top-blocked') .then(data => { // 处理多种可能的数据格式,特别优化对用户提供格式的支持 let processedData = []; @@ -909,7 +909,7 @@ function loadTopResolvedDomains(isUpdate = false) { tbody.innerHTML = `加载中...`; } - return apiRequest('/top-resolved') + return apiRequest('/api/top-resolved') .then(data => { // 处理多种可能的数据格式 let processedData = []; diff --git a/static/js/modules/hosts.js b/static/js/modules/hosts.js index 6d345e3..7c0f374 100644 --- a/static/js/modules/hosts.js +++ b/static/js/modules/hosts.js @@ -29,7 +29,7 @@ function loadHosts() { showLoading(tbody); // 更新API路径,使用完整路径 - apiRequest('/shield/hosts', 'GET') + apiRequest('/api/shield/hosts', 'GET') .then(data => { // 处理不同格式的响应数据 let hostsData; @@ -156,7 +156,7 @@ function addHostsEntry() { } // 修复重复API调用问题,只调用一次 - apiRequest('/shield/hosts', 'POST', { ip: ip, domain: domain }) + apiRequest('/api/shield/hosts', 'POST', { ip: ip, domain: domain }) .then(data => { // 处理不同的响应格式 if (data.success || data.status === 'success') { @@ -209,7 +209,7 @@ function deleteHostsEntry(ip, domain) { } // 更新API路径 - apiRequest('/shield/hosts', 'DELETE', { ip: ip, domain: domain }) + apiRequest('/api/shield/hosts', 'DELETE', { ip: ip, domain: domain }) .then(data => { // 处理不同的响应格式 if (data.success || data.status === 'success') { diff --git a/static/js/modules/query.js b/static/js/modules/query.js index 2532a89..77ce7b1 100644 --- a/static/js/modules/query.js +++ b/static/js/modules/query.js @@ -40,7 +40,7 @@ function runDnsQuery() { showQueryLoading(); // 更新API路径,使用完整路径 - apiRequest('/query', 'GET', { domain: domain }) + apiRequest('/api/query', 'GET', { domain: domain }) .then(data => { // 处理可能的不同响应格式 renderQueryResult(data); diff --git a/static/js/modules/rules.js b/static/js/modules/rules.js index 94ec160..30d2c3c 100644 --- a/static/js/modules/rules.js +++ b/static/js/modules/rules.js @@ -41,7 +41,7 @@ async function loadRules() { showLoading(rulesPanel); // 更新API路径,使用正确的API路径 - const data = await apiRequest('/shield', 'GET'); + const data = await apiRequest('/api/shield', 'GET'); // 处理后端返回的复杂对象数据格式 let allRules = []; @@ -207,7 +207,7 @@ async function addNewRule() { const processedRule = preprocessRule(rule); // 使用正确的API路径 - const response = await apiRequest('/shield', 'POST', { rule: processedRule }); + const response = await apiRequest('/api/shield', 'POST', { rule: processedRule }); // 处理不同的响应格式 if (response.success || response.status === 'success') { @@ -258,7 +258,7 @@ async function deleteRule(index) { } // 使用正确的API路径 - const response = await apiRequest('/shield', 'DELETE', { rule }); + const response = await apiRequest('/api/shield', 'DELETE', { rule }); // 处理不同的响应格式 if (response.success || response.status === 'success') { @@ -319,8 +319,8 @@ async function reloadRules() { const rulesPanel = document.getElementById('rules-panel'); showLoading(rulesPanel); - // 使用正确的API路径和方法 - PUT请求到/shield - await apiRequest('/shield', 'PUT'); + // 使用正确的API路径和方法 - PUT请求到/api/shield + await apiRequest('/api/shield', 'PUT'); // 重新加载规则列表 await loadRules();