This commit is contained in:
Alex Yang
2025-11-25 00:35:37 +08:00
parent 9f81b449f1
commit c570f303e7
7 changed files with 56 additions and 50 deletions

View File

@@ -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()
}
// 保存更新后的黑名单列表
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)
}

View File

@@ -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 => {
// 更新服务器状态指示器

View File

@@ -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 {

View File

@@ -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 = `<td colspan="100%" style="color: #7f8c8d; font-style: italic;">加载中...</td>`;
}
return apiRequest('/top-blocked')
return apiRequest('/api/top-blocked')
.then(data => {
// 处理多种可能的数据格式,特别优化对用户提供格式的支持
let processedData = [];
@@ -909,7 +909,7 @@ function loadTopResolvedDomains(isUpdate = false) {
tbody.innerHTML = `<td colspan="100%" style="color: #7f8c8d; font-style: italic;">加载中...</td>`;
}
return apiRequest('/top-resolved')
return apiRequest('/api/top-resolved')
.then(data => {
// 处理多种可能的数据格式
let processedData = [];

View File

@@ -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') {

View File

@@ -40,7 +40,7 @@ function runDnsQuery() {
showQueryLoading();
// 更新API路径使用完整路径
apiRequest('/query', 'GET', { domain: domain })
apiRequest('/api/query', 'GET', { domain: domain })
.then(data => {
// 处理可能的不同响应格式
renderQueryResult(data);

View File

@@ -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();