- 线路
-
-
-
- 中国大陆
- 港澳台及境外
-
+
-
+
\ No newline at end of file
diff --git a/EdgeAdmin/web/views/@default/httpdns/apps/index.html b/EdgeAdmin/web/views/@default/httpdns/apps/index.html
index c5f557d..622843b 100644
--- a/EdgeAdmin/web/views/@default/httpdns/apps/index.html
+++ b/EdgeAdmin/web/views/@default/httpdns/apps/index.html
@@ -26,11 +26,11 @@
-
-
+
+
-
+
diff --git a/EdgeAdmin/web/views/@default/httpdns/guide/index.html b/EdgeAdmin/web/views/@default/httpdns/guide/index.html
index 7f786f6..8d0b77d 100644
--- a/EdgeAdmin/web/views/@default/httpdns/guide/index.html
+++ b/EdgeAdmin/web/views/@default/httpdns/guide/index.html
@@ -87,14 +87,6 @@
-
- AES 数据加密 Secret
-
- {{aesSecretVisible ? selectedApp.aesSecret : selectedApp.aesSecretMasked}}
-
-
-
-
请求验签
diff --git a/EdgeAdmin/web/views/@default/httpdns/guide/index.js b/EdgeAdmin/web/views/@default/httpdns/guide/index.js
index 43e2069..e1fe07a 100644
--- a/EdgeAdmin/web/views/@default/httpdns/guide/index.js
+++ b/EdgeAdmin/web/views/@default/httpdns/guide/index.js
@@ -3,7 +3,6 @@
this.selectedApp = {}
this.currentStep = 1
this.signSecretVisible = false
- this.aesSecretVisible = false
if (typeof this.apps == "undefined") {
this.apps = []
@@ -29,7 +28,6 @@
}
this.signSecretVisible = false
- this.aesSecretVisible = false
this.currentStep = 1
}
diff --git a/EdgeAdmin/web/views/@default/httpdns/sandbox/index.html b/EdgeAdmin/web/views/@default/httpdns/sandbox/index.html
index 6d06736..fc69335 100644
--- a/EdgeAdmin/web/views/@default/httpdns/sandbox/index.html
+++ b/EdgeAdmin/web/views/@default/httpdns/sandbox/index.html
@@ -4,21 +4,31 @@
-
+
\ No newline at end of file
+
diff --git a/EdgeAdmin/web/views/@default/httpdns/sandbox/index.js b/EdgeAdmin/web/views/@default/httpdns/sandbox/index.js
index dfb910e..9bf9cf0 100644
--- a/EdgeAdmin/web/views/@default/httpdns/sandbox/index.js
+++ b/EdgeAdmin/web/views/@default/httpdns/sandbox/index.js
@@ -2,6 +2,7 @@ Tea.context(function () {
this.newRequest = function () {
return {
appId: "",
+ clusterId: "",
domain: "",
clientIp: "",
qtype: "A"
@@ -20,13 +21,48 @@ Tea.context(function () {
}
this.isRequesting = false
+ this.currentDomains = []
- if (typeof this.apps == "undefined") {
+ if (typeof this.apps === "undefined") {
this.apps = []
}
+ if (typeof this.clusters === "undefined") {
+ this.clusters = []
+ }
+
+ this.onAppChanged = function () {
+ let selectedApp = null
+ for (let i = 0; i < this.apps.length; i++) {
+ if (this.apps[i].appId === this.request.appId) {
+ selectedApp = this.apps[i]
+ break
+ }
+ }
+
+ if (selectedApp == null) {
+ this.currentDomains = []
+ this.request.domain = ""
+ this.request.clusterId = ""
+ return
+ }
+
+ this.currentDomains = Array.isArray(selectedApp.domains) ? selectedApp.domains : []
+
+ if (this.currentDomains.length > 0) {
+ if (this.currentDomains.indexOf(this.request.domain) < 0) {
+ this.request.domain = this.currentDomains[0]
+ }
+ } else {
+ this.request.domain = ""
+ }
+
+ if (typeof selectedApp.clusterId !== "undefined" && selectedApp.clusterId !== null) {
+ this.request.clusterId = String(selectedApp.clusterId)
+ }
+ }
this.normalizeResultRows = function (data) {
- if (typeof data == "undefined" || data == null) {
+ if (typeof data === "undefined" || data == null) {
return []
}
@@ -35,10 +71,7 @@ Tea.context(function () {
}
let rows = []
- let ips = []
- if (Array.isArray(data.ips)) {
- ips = data.ips
- }
+ let ips = Array.isArray(data.ips) ? data.ips : []
let domain = this.request.domain
let qtype = this.request.qtype
let ttl = data.ttl || 0
@@ -55,16 +88,21 @@ Tea.context(function () {
line: line
})
})
+
return rows
}
this.sendTestRequest = function () {
- if (this.request.appId.length == 0) {
- teaweb.warn("请选择目标应用")
+ if (this.request.appId.length === 0) {
+ teaweb.warn("Please select target app")
return
}
- if (this.request.domain.length == 0) {
- teaweb.warn("请填写解析域名")
+ if (this.request.clusterId.length === 0) {
+ teaweb.warn("Please select cluster")
+ return
+ }
+ if (this.request.domain.length === 0) {
+ teaweb.warn("Please select domain")
return
}
@@ -87,6 +125,7 @@ Tea.context(function () {
this.resetForm = function () {
this.request = this.newRequest()
+ this.currentDomains = []
this.response = {
hasResult: false,
code: -1,
diff --git a/EdgeHttpDNS/HTTPDNS主计划-V1.2.md b/EdgeHttpDNS/HTTPDNS主计划-V1.2.md
index 360646e..40879b5 100644
--- a/EdgeHttpDNS/HTTPDNS主计划-V1.2.md
+++ b/EdgeHttpDNS/HTTPDNS主计划-V1.2.md
@@ -1,148 +1,147 @@
-# HTTPDNS 主计划(V1.2 现行版)
+# HTTPDNS 主计划(V1.2 现行设计)
## 1. 目标
-1. 形成 HTTPDNS 管理端可用闭环:集群、全局配置、应用、域名、自定义解析、日志、解析测试。
-2. 保持独立 HTTPDNS 模块设计,不挂载到传统 DNS(53)职责中。
-3. 文档仅保留当前已采用的设计与页面,不包含未落地方案。
+1. 构建独立的 HTTPDNS 管理闭环:集群、应用、域名、自定义解析、访问日志、运行日志、解析测试。
+2. 方案以当前已确认的页面与交互为准,不保留历史分支设计。
+3. 优先保证可运维、可灰度、可观测,先落地稳定版本。
-## 2. 当前范围(仅管理平台)
-1. 菜单顺序固定为:
+## 2. 信息架构(菜单)
+1. 左侧 HTTPDNS 菜单顺序:
- 集群管理
- - 全局配置
- 应用管理
- - SDK接入引导
- 访问日志
- 运行日志
- 解析测试
-2. 现阶段以管理端页面与 Mock 数据联调为主。
+2. 不再保留独立“全局配置”菜单。
+3. 不再保留独立“SDK接入引导”菜单。
## 3. 核心设计约束
-1. 应用侧 SNI 防护仅采用“隐匿 SNI”固定策略(不再提供 level1/level3 选择)。
-2. 服务入口按“集群服务域名”管理,不使用全局单一网关地址。
-3. 应用认证采用:
- - 请求验签开关
- - 加签 Secret
- - AES 数据加密 Secret
-4. 自定义解析规则支持 SDNS 参数与解析记录多条配置(各最多 10 条)。
+1. SNI 防护策略固定为“隐匿 SNI”(不提供 level1/level3、mask/empty切换入口)。
+2. 服务入口按“集群服务域名”管理,不使用全局单入口。
+3. 回源协议默认 HTTPS,不提供开关。
+4. 域名校验默认开启,不在用户侧暴露开关。
+5. 自定义解析先做精简版:不支持 SDNS 参数匹配。
-## 4. 页面设计(现状)
+## 4. 集群管理
-### 4.1 集群管理
-1. 集群列表字段:
+### 4.1 集群列表
+1. 字段:集群名称、服务域名、节点数、在线节点数、状态、操作。
+2. 操作:节点列表、集群设置、删除集群。
+
+### 4.2 节点列表
+1. 字段:节点名称、IP、CPU、内存、负载、状态、操作。
+2. IP 列不展示“[下线]/[宕机]”附加标识。
+
+### 4.3 集群设置
+1. 页面布局对齐智能DNS:左侧菜单 + 右侧配置区(`left-box with-menu` / `right-box with-menu`)。
+2. 配置分组:
+ - 基础设置
+ - TLS
+3. 基础设置字段:
- 集群名称
- 服务域名
- - 节点数
- - 在线节点数
- - 状态
- - 操作
-2. 集群设置字段:
- - 集群名称
- - 集群服务域名
+ - 默认解析 TTL(秒)
- 降级超时容忍度(毫秒)
- - 本地内存缓存(秒)
- 节点安装根目录(默认 `/opt/edge-httpdns`)
- 启用当前集群
-3. 节点页提供基础筛选、状态展示、详情与删除。
+ - 默认集群(勾选)
+4. TLS 配置:
+ - 样式与交互对齐智能DNS TLS页
+ - 维护并绑定该集群服务域名使用的证书
+ - 保证节点回源链路为 HTTPS
-### 4.2 全局配置
-1. 用户设置:
- - 默认部署集群
- - 启用用户域名校验
-2. 基础默认:
- - SNI 防护配置(文案展示为“隐匿 SNI”)
- - 全局默认解析 TTL
- - 全局降级超时
+## 5. 应用管理
-### 4.3 应用管理
-1. 应用列表字段:
- - 应用名称
- - AppID
- - 绑定域名数(可点击)
- - 状态
- - 操作(域名管理 / 应用设置)
-2. 添加应用:
- - 应用名称
- - 所属集群
- - 所属用户(可选)
-3. 应用设置分两块:
- - 基础配置:AppID、应用启用、SNI 防护配置(隐匿 SNI)
- - 认证与密钥:请求验签开关、加签 Secret、AES Secret(查看/复制/重置/更新时间)
+### 5.1 应用列表
+1. 字段:应用名称、AppID、绑定域名数、状态、操作。
+2. 操作:域名列表、应用设置、SDK集成、删除应用。
+3. 删除应用页面交互风格对齐“删除集群”页面。
-### 4.4 域名管理与自定义解析
-1. 域名管理:
+### 5.2 应用设置
+1. 页面布局对齐智能DNS设置页风格(左侧菜单 + 右侧配置区)。
+2. 分组:
+ - 基础配置
+ - 认证与密钥
+3. 基础配置字段:
+ - AppID(只读)
+ - 主集群
+ - 备集群(可选)
+ - 应用启用
+ - SNI 防护配置(文案展示:隐匿 SNI)
+4. 认证与密钥字段:
+ - 请求验签(状态展示 + 独立启停按钮 + 确认提示)
+ - 加签 Secret(查看、复制、重置、最近更新时间)
+5. 交互约束:
+ - 强制 HTTPS 传输,不再提供独立“数据加密 Secret”配置项。
+ - 密钥操作区使用紧凑图标样式,减少视觉噪音。
+
+## 6. 域名管理与自定义解析
+
+### 6.1 域名管理
+1. 页面采用框架标准顶部 tab + 面包屑样式。
+2. 字段:
- 域名列表
- - 规则策略(显示该域名自定义解析规则数)
+ - 规则策略(仅展示数字,表示该域名规则数,可点击)
- 操作(自定义解析、解绑)
-2. 自定义解析列表字段:
- - 线路
+3. 入口:在域名行操作中直接进入“自定义解析”。
+
+### 6.2 自定义解析(精简版)
+1. 规则字段:
- 规则名称
- - SDNS 参数
- - 解析记录
+ - 线路
+ - 解析记录值
- TTL
- 状态
- - 操作(编辑/启停/删除)
-3. 新增/编辑规则弹窗:
- - 规则名称
- - 线路联动:
- - 中国大陆:运营商 -> 大区 -> 省份
- - 港澳台及境外:洲 -> 国家/地区(亚洲含中国香港/中国澳门/中国台湾)
- - SDNS 参数配置:最多 10 条
- - 解析记录值:最多 10 条,支持 A/AAAA,可开启权重(1-100)
- - TTL(1-86400)
- - 规则状态
+2. 线路联动:
+ - 第一层:`中国地区` / `境外`
+ - 中国地区:运营商 -> 大区 -> 省份
+ - 境外:洲 -> 国家/地区(亚洲内使用中国香港/中国澳门/中国台湾)
+3. 解析记录:
+ - 每条规则最多 10 条
+ - 支持 A / AAAA
+ - 可开启权重调度
+4. 不包含 SDNS 参数配置。
-## 5. SDK接入引导(现状)
-1. 仅保留两步:
- - 01 查看配置
- - 02 开发接入
-2. 查看配置展示:
- - App ID(可复制)
- - 应用名称
- - 集群服务地址(可复制)
- - 加签 Secret(查看/复制)
- - AES 数据加密 Secret(查看/复制)
- - 请求验签状态
+## 7. 访问日志
+1. 菜单与页面文案统一为“访问日志”(不再使用“解析日志”)。
+2. 页面结构:筛选区与列表区分离,间距与智能DNS访问日志风格一致。
+3. 列字段:集群、节点、域名、类型、概要。
+4. 概要展示:
+ - 使用单行拼接
+ - 按“访问信息 -> 解析结果”顺序
+ - 不显示字段名堆叠
-## 6. 日志页面(现状)
+## 8. 运行日志
+1. 字段与智能DNS运行日志保持一致。
+2. 级别样式使用文字着色,不使用大块背景色。
-### 6.1 访问日志
-1. 主列:
- - 集群
- - 节点
- - 域名
- - 类型
- - 概要
-2. 概要按单行拼接展示,按“访问信息 -> 解析结果”顺序输出,不使用字段名堆叠。
+## 9. 解析测试
+1. 去掉“API在线沙盒”标题与右侧等待占位图标区。
+2. 解析配置区标题统一为“解析测试”。
+3. 测试参数保留:目标应用、所属集群、解析域名、模拟客户端IP、解析类型(A/AAAA)。
+4. 所属集群使用下拉框选择。
+5. 解析域名使用下拉框选择(按当前目标应用联动展示)。
+6. 去掉 SDNS 参数。
+7. 结果区保留核心结果展示,参考阿里云风格的简洁结果布局。
-### 6.2 运行日志
-1. 字段:
- - 时间
- - 集群
- - 节点
- - 级别
- - 类型
- - 模块
- - 详情
- - 次数
- - 请求ID
+## 10. SDK 集成
+1. SDK 集成不作为左侧独立菜单。
+2. 在“应用管理”操作列进入 SDK 集成页。
+3. 页面只保留:
+ - SDK 下载
+ - 集成文档
+4. 卡片与按钮采用紧凑布局,避免按钮区域拥挤。
-## 7. 解析测试(现状)
-1. 左侧配置项:
- - 目标应用
- - 解析域名
- - 模拟客户端 IP
- - 解析类型(A/AAAA)
- - SDNS 参数(最多 10 条)
-2. 右侧结果区:
- - 解析成功/失败
- - Request ID
- - 请求URL
- - 客户端 IP / 地区 / 线路
- - 解析记录表(解析域名、解析类型、IP地址、TTL、地区、线路)
-3. 已去掉无关展示块(如安全策略、验签响应头详情块)。
+## 11. SDK 与服务端接口(现行)
+1. 解析接口:`/resolve`
+ - SDK 请求域名解析结果的主接口。
+2. 启动配置接口:`/bootstrap`(规划/联调口径)
+ - 用于 SDK 获取可用服务域名与策略参数(替代节点IP调度模式)。
+3. SDK 地址策略:优先主集群服务域名,不可用时切备集群;失败后按客户端降级策略处理。
-## 8. 本文不包含的内容
-1. 不包含 ECH 控制台与 ECH 分阶段交付设计。
-2. 不包含 SNI level1/level3、多级切换与 Public SNI 域名池页面设计。
-3. 不包含第三方 DNS 凭证复用与相关编排描述。
-4. 不包含用户平台(User)页面方案。
+## 12. 本文明确不包含
+1. 不包含全局配置独立页面设计。
+2. 不包含 SDK 接入向导独立菜单设计。
+3. 不包含 SNI level1/level3、ECH 控制台、Public SNI 池分级配置。
+4. 不包含 SDNS 参数匹配链路。
+5. 不包含第三方 DNS 依赖与复用方案。
diff --git a/EdgeHttpDNS/HTTPDNS后端开发计划.md b/EdgeHttpDNS/HTTPDNS后端开发计划.md
new file mode 100644
index 0000000..27c7124
--- /dev/null
+++ b/EdgeHttpDNS/HTTPDNS后端开发计划.md
@@ -0,0 +1,254 @@
+# HTTPDNS后端开发计划(V1.0)
+
+## 0. 文档信息
+- 目标文件:`EdgeHttpDNS/HTTPDNS后端开发计划.md`
+- 交付范围:`EdgeAdmin + EdgeAPI + EdgeNode + SDK对接接口`
+- 交付策略:一次性全量交付(非分阶段)
+- 核心约束:
+ - 仅新协议
+ - 无 `/bootstrap`
+ - `/resolve` 使用 GET 参数
+ - 线路匹配仅基于客户端 IP 归属
+ - 独立 `edgeHTTPDNS*` 数据表
+ - 新增独立节点角色 `NodeRoleHTTPDNS`
+ - 访问日志 MySQL + ClickHouse 双写(查询优先 ClickHouse)
+
+## 1. 目标与成功标准
+1. 将 HTTPDNS 从当前 Admin 侧 mock/store 方案落地为真实后端能力。
+2. 打通“配置 -> 下发 -> 解析 -> 日志 -> 查询”闭环。
+3. 与当前前端设计严格对齐:
+ - 菜单:集群管理、应用管理、访问日志、运行日志、解析测试
+ - SNI 固定为“隐匿 SNI”
+ - 自定义解析不含 SDNS 参数
+4. 成功标准:
+ - 管理页面均通过 RPC 读取真实数据,无本地 mock 依赖
+ - `/resolve` 可按应用/域名/线路返回解析结果
+ - 访问日志与运行日志可查询、可筛选、可分页
+ - 节点配置与状态可下发和回传
+ - 主备集群服务域名可在应用设置中配置并生效
+ - EdgeNode 支持 SNI 与 Host 解耦路由,并可执行 WAF 动态验签与隐匿 SNI 转发
+
+## 2. 架构与边界
+### 2.1 服务边界
+1. EdgeAdmin:仅负责页面动作与 RPC 编排,不存业务状态。
+2. EdgeAPI:负责数据存储、策略匹配、接口服务、日志汇聚。
+3. EdgeNode(HTTPDNS节点):负责执行解析、接收策略任务、上报运行日志/访问日志,并执行 SNI/Host 解耦路由、WAF 动态验签、隐匿 SNI 转发。
+4. SDK:手动配置应用关联主备服务域名,调用 `/resolve` 获取结果。
+
+### 2.2 不做项
+1. 不做 `/bootstrap` 接口。
+2. 不做 ECH / SNI 分级策略。
+3. 不做 SDNS 参数匹配。
+4. 不做第三方 DNS 依赖复用。
+
+## 3. 公开接口与契约(需新增/调整)
+### 3.1 HTTP 解析接口
+1. `GET /resolve`
+2. 请求参数:
+ - `appId`(必填)
+ - `dn`(必填)
+ - `qtype`(可选,A/AAAA,默认 A)
+ - `cip`(可选)
+ - `sid`、`sdk_version`、`os`(可选,用于日志)
+ - `nonce`、`exp`、`sign`(可选,验签开启时必需)
+3. 响应结构(统一):
+ - `code`、`message`、`requestId`
+ - `data`:
+ - `domain`
+ - `qtype`
+ - `ttl`
+ - `records[]`(`type`,`ip`,`weight?`,`line?`,`region?`)
+ - `client`(`ip`,`region`,`carrier`,`country`)
+ - `summary`(命中规则摘要)
+4. 错误码最低集合:
+ - app 无效/禁用
+ - 域名未绑定
+ - 验签失败
+ - 无可用解析记录
+ - 内部解析失败/超时
+
+### 3.2 管理 RPC(EdgeAdmin -> EdgeAPI)
+1. 新增服务:
+ - `HTTPDNSClusterService`
+ - `HTTPDNSNodeService`
+ - `HTTPDNSAppService`
+ - `HTTPDNSDomainService`
+ - `HTTPDNSRuleService`
+ - `HTTPDNSAccessLogService`
+ - `HTTPDNSRuntimeLogService`
+ - `HTTPDNSSandboxService`
+2. 最小方法集:
+ - 集群:增删改查、设置默认集群、TLS证书绑定、节点列表/状态
+ - 应用:增删改查、主备集群设置、启停、验签开关、密钥重置
+ - 域名:绑定/解绑/列表
+ - 自定义解析:规则增删改查、启停、排序
+ - 日志:访问日志分页查询、运行日志分页查询
+ - 测试:在线解析测试调用(入参包含 appId、clusterId、domain、qtype、clientIp)
+
+### 3.3 节点日志上报 RPC(EdgeNode -> EdgeAPI)
+1. `CreateHTTPDNSAccessLogs`(批量)
+2. `CreateHTTPDNSRuntimeLogs`(批量)
+3. 幂等键:`requestId + nodeId`
+4. 支持高吞吐批量提交和失败重试
+
+### 3.4 节点路由与 WAF 策略下发契约(EdgeAPI -> EdgeNode)
+1. 下发内容最小集合:
+ - `appId/domain/serviceDomain`
+ - `sniMode`(固定为隐匿 SNI)
+ - `hostRouteMode`(SNI 与 Host 解耦)
+ - `wafVerifyEnabled`
+ - `wafVerifyPolicy`(验签字段、时效窗口、失败动作)
+2. 节点执行口径:
+ - 入站按 `serviceDomain` 接入,按 Host/业务域名做路由匹配
+ - TLS 握手与业务 Host 解耦,避免真实业务域名暴露在 SNI
+ - 命中需要验签的应用时,先执行 WAF 动态验签,再继续解析链路
+3. 失败处置:
+ - 验签失败按策略拒绝并记录运行日志、访问日志错误码
+ - 路由未命中返回统一错误码并上报审计日志
+
+## 4. 数据模型设计(独立 HTTPDNS 表)
+1. `edgeHTTPDNSClusters`
+ - `id,name,isOn,isDefault,serviceDomain,defaultTTL,fallbackTimeoutMs,installDir,tlsPolicyJSON,createdAt,updatedAt`
+2. `edgeHTTPDNSNodes`
+ - `id,clusterId,name,isOn,isUp,isInstalled,isActive,statusJSON,installStatusJSON,installDir,uniqueId,secret,createdAt,updatedAt`
+3. `edgeHTTPDNSApps`
+ - `id,name,appId,isOn,primaryClusterId,backupClusterId,sniMode(fixed_hide),createdAt,updatedAt`
+4. `edgeHTTPDNSAppSecrets`
+ - `id,appId,signEnabled,signSecretEnc,signUpdatedAt,updatedAt`
+5. `edgeHTTPDNSDomains`
+ - `id,appId,domain,isOn,createdAt,updatedAt`
+6. `edgeHTTPDNSCustomRules`
+ - `id,appId,domainId,ruleName,lineScope,lineCarrier,lineRegion,lineProvince,lineContinent,lineCountry,ttl,isOn,priority,updatedAt`
+7. `edgeHTTPDNSCustomRuleRecords`
+ - `id,ruleId,recordType,recordValue,weight,sort`
+8. `edgeHTTPDNSAccessLogs`
+ - `id,requestId,clusterId,nodeId,appId,domain,qtype,clientIP,clientRegion,carrier,sdkVersion,os,resultIPs,status,errorCode,costMs,createdAt,day`
+9. `edgeHTTPDNSRuntimeLogs`
+ - `id,clusterId,nodeId,level,type,tag,description,count,createdAt,day`
+
+### 4.1 索引与唯一约束
+1. 唯一:`edgeHTTPDNSApps.appId`
+2. 唯一:`edgeHTTPDNSDomains(appId,domain)`
+3. 唯一:`edgeHTTPDNSAccessLogs(requestId,nodeId)`
+4. 索引:
+ - 访问日志:`day,clusterId,nodeId,domain,status,createdAt`
+ - 规则匹配:`domainId,isOn,priority,lineScope,...`
+ - 应用查询:`name,appId,isOn`
+
+## 5. 解析引擎实现(EdgeAPI)
+1. 输入校验:`appId/dn/qtype`
+2. 应用与域名校验:
+ - app 存在且启用
+ - 域名已绑定到 app
+3. 线路归属:
+ - `cip` 优先,其次 remote IP
+ - 映射字段:运营商/大区/省份/洲/国家
+4. 规则匹配:
+ - 精确匹配 > 半精确 > 默认
+ - 同级按 `priority` 从小到大
+5. 记录返回:
+ - 权重关闭:返回全部记录
+ - 权重开启:按权重算法返回单条或子集(固定口径)
+6. TTL 取值:
+ - 命中规则取规则 TTL
+ - 未命中规则取集群默认 TTL
+7. 验签:
+ - `signEnabled=true` 时必须通过签名校验
+ - `signEnabled=false` 时跳过签名校验
+8. 访问日志:
+ - 解析结束异步写日志
+ - 双写 MySQL/ClickHouse
+
+## 6. 节点与任务链路
+1. 在 `EdgeCommon/pkg/nodeconfigs` 增加 `NodeRoleHTTPDNS`。
+2. 在任务系统增加 HTTPDNS 任务类型:
+ - 配置变更
+ - 应用变更
+ - 域名变更
+ - 规则变更
+ - 证书变更
+ - 路由与 WAF 策略变更
+3. EdgeNode 增加 HTTPDNS 子服务:
+ - 接收配置快照
+ - 执行解析
+ - 上报运行/访问日志
+ - 执行 SNI/Host 解耦路由
+ - 执行 WAF 动态验签
+ - 执行隐匿 SNI 转发
+4. 复用现有安装升级框架,但节点角色、任务通道、日志 tag 独立。
+
+## 7. EdgeAdmin 后端改造
+1. 将 `internal/web/actions/default/httpdns/*` 的 store/mock 读写改为 RPC。
+2. 删除/停用旧能力路由:
+ - `/httpdns/policies`
+ - `/httpdns/guide`
+ - `/httpdns/ech`
+3. 保留必要跳转,避免旧链接 404。
+4. `sandbox/test` 改为调用真实解析服务(可保留测试开关)。
+5. 解析测试页面交互固定为:
+ - 配置区标题“解析测试”
+ - 所属集群使用下拉框
+ - 解析域名使用下拉框并按目标应用联动
+
+## 8. 安全与审计
+1. Secret 持久化使用加密存储(至少密文列),返回时脱敏。
+2. 操作审计记录:
+ - 验签开关启停
+ - Sign Secret 重置
+ - 应用主备集群修改
+3. 验签失败日志保留 `requestId,errorCode,sourceIP`。
+4. 防滥用:
+ - `/resolve` 增加基础限流与异常请求过滤(按 appId + IP 维度)。
+5. 节点侧安全执行:
+ - WAF 动态验签失败必须留存审计日志(含 requestId/appId/sourceIP)
+ - SNI/Host 解耦路由命中结果需可追踪(用于问题回溯)
+
+## 9. 测试与验收
+### 9.1 单元测试
+1. 规则匹配优先级与线路匹配
+2. 验签成功/失败路径
+3. 权重返回算法
+4. DAO CRUD 与唯一约束
+
+### 9.2 集成测试
+1. EdgeAdmin -> RPC -> DB 全链路
+2. `/resolve` 各错误码分支
+3. 节点日志上报双写(MySQL+CH)
+4. CH 不可用时 MySQL 回退查询
+5. EdgeAPI 策略下发 -> EdgeNode 路由/WAF 执行 -> 日志落库全链路
+
+### 9.3 回归测试
+1. 智能DNS功能不受影响
+2. 菜单与权限不串模块
+3. 旧入口跳转正确,无新增 404
+
+### 9.4 验收用例
+1. 应用配置主备服务域名后,SDK可解析成功
+2. 主集群故障时可切备集群
+3. 自定义解析按线路返回预期 IP
+4. 访问日志筛选与概要展示正确
+5. 运行日志级别/字段与智能DNS一致
+6. EdgeNode 可在 SNI 与 Host 解耦场景下正确路由到目标应用
+7. 开启 WAF 动态验签后,合法请求通过、非法签名请求被拒绝且有审计日志
+
+## 10. 发布与回滚
+1. 发布顺序:
+ - DB migration
+ - EdgeAPI(DAO+RPC+resolve)
+ - EdgeNode(角色+上报)
+ - EdgeAdmin(RPC切换)
+2. 开关控制:
+ - `httpdns.resolve.enabled`
+ - `httpdns.log.clickhouse.enabled`
+3. 回滚策略:
+ - 关闭 `resolve` 新实现开关
+ - 访问日志读取切回 MySQL
+ - Admin 保留只读能力
+
+## 11. 默认值与固定决策
+1. 无 `/bootstrap`,SDK手动配置主备服务域名。
+2. `SNI` 固定“隐匿 SNI”。
+3. 自定义解析无 SDNS 参数。
+4. 线路仅客户端 IP 归属。
+5. 日志双写,查询优先 ClickHouse。
+6. 节点角色独立:`NodeRoleHTTPDNS`。
diff --git a/EdgeHttpDNS/自定义解析功能.md b/EdgeHttpDNS/自定义解析功能.md
deleted file mode 100644
index 763a61e..0000000
--- a/EdgeHttpDNS/自定义解析功能.md
+++ /dev/null
@@ -1,114 +0,0 @@
-在域名管理中 加一个 自定义解析功能。
-功能简介:若需为域名提供特定的解析结果,可以使用HTTPDNS提供的自定义解析功能。该功能支持通过配置规则来实现对特定域名的自定义解析。
-应用场景:灰度测试:假设您的域名是 www.example.com,因为业务增长发布了新的服务,新的服务IP为1.1.X.X,在服务全量发布前,您希望对电信_上海访问域名的流量进行特定APP版本号的灰度测试。对于这些流量访问www.example.com时发起的域名解析请求返回1.1.X.X。
-
-流量调度:假设某个汽车企业服务域名是 www.example.com,希望DNS解析过程中可以根据特定的业务逻辑返回位于不同区域的服务器的 IP 地址。例如根据汽车常驻地返回不同的服务IP,某辆汽车的常驻地区在广州,对于该汽车访问 www.example.com 时发起的 DNS 查询请求返回位于广州的服务器的 IP 地址。
-
-
-策略说明
-可以通过某种规则来达到自定义解析的目的。您可以对网络线路进行更精细的配置,并通过配置不同的解析参数,使来自不同运营商和地域的用户流量精准路由至不同的服务地址。
-
-使用方式如下:
-
-在 HTTPDNS 控制台 中,为指定域名创建一条自定义解析规则策略。
-
-客户端通过 SDK 发起 DNS 查询请求时,携带相应的自定义解析参数。
-
-HTTPDNS 服务端接收到请求后,会根据预设的匹配规则,返回最符合业务需求的解析结果。
-您可以做以下配置:
-
-基本信息
-
-参数
-
-说明
-
-域名
-
-您希望自定义解析的域名,例如:www.aliyun.com。
-
-说明
-域名选择下拉的数据源来自于接入域名中已经添加的域名,如果想要自定义解析的域名不在下拉列表中,可以到域名列表中添加后,再为该域名添加自定义解析记录。
-
-如果要为某个泛域名的子域名添加自定义解析记录,例如:*.aliyun.com,但你想要自定义域名是 a.aliyun.com,则需要将 a.aliyun.com 添加到域名列表中,再为该域名添加自定义解析记录。
-
-域名选择下拉字段选不到对应的域名有以下几种情况:
-
-想要添加的域名不在域名列表中,您可以到接入域名中添加对应的域名即可。
-
-想要添加的域名是某个泛域名的子域名,将该子域名添加到域名列表即可。
-
-想要添加的域名已经存在自定义解析记录,需要去自定义解析记录列表管理对应的域名。
-
-线路
-
-可针对运营商和地域进行线路配置。
-
-中国内地线路:按“运营商 > 大区 > 省份”进行配置。
-
-运营商:可以自定义运营商,例如:中国电信。如果运营商设置为默认,表示当前线路覆盖所有运营商。
-
-大区:按照地域划分,例如:东北、华北、华东等,省份归属在对应大区下。如果大区设置为默认,表示当前线路覆盖所有大区。
-
-省份:可以自定义省份,例如:北京、河北,如果省份设置为默认,表示当前线路覆盖所有省份。
-
-海外线路:选择地域为“境外”时生效,按“洲 > 国家或地区”进行配置。
-
-可以选择大洲,例如:亚洲、欧洲、南美洲等;也可以在大洲下选择具体国家或地区,例如:日本、英国等。
-
-如果大洲、国家或地区设置为默认,表示当前线路覆盖所选范围内的全部区域。
-
-说明
-在同一个域名下,对于相同地域的用户,线路生效的优先级是:运营商>地理位置>默认。例如,电信-华北-北京>电信-华北-默认>默认-华北-北京>默认-默认-默认。
-
-例如:如果在同一个域名下同时存在两条规则策略,线路分别是电信-华北-北京和电信-华北-默认,那么对于北京的电信用户会使用电信-华北-北京线路的规则策略。
-
-自定义解析规则
-
-一条规则策略最多支持配置 10 条自定义解析规则。
-
-参数
-
-说明
-
-规则名称
-
-说明当前规则的名称,可以用来表达规则的用途,例如:通过SDK版本调度。
-
-规则排序
-
-多个规则之间可以调整顺序,匹配的逻辑是从上往下串行匹配,顺序决定了哪个规则会被优先命中,调整顺序后会按照新的顺序匹配。
-
-SDNS参数配置
-
-用来匹配客户端请求解析接口携带的SDNS参数,决定该条规则是否被命中,如果匹配成功,则返回该条规则中的解析记录值。详细的匹配逻辑请查看规则策略匹配逻辑说明。
-
-参数名称:SDNS参数的名称,长度限制为 2 ~ 64 个字符。
-
-参数值:SDNS参数的值,长度限制为 1 ~ 64 个字符。
-
-说明
-一条规则最多添加 10 个 SDNS参数。
-
-解析接口可以添加SDNS参数,具体查看 客户端传递自定义解析参数。
-
-解析记录值
-
-自定义解析的返回值集合,每个记录值代表记录集中的一条解析记录,必填。
-
-记录类型:返回解析记录值的类型,支持A和AAAA记录。
-
-记录值:返回的记录值
-
-您可以添加多个记录值,在未开启权重的情况下,添加的多个记录值将会合并在一起返回。
-
-还可以按照权重调度,只需要打开按照权重调度开关即可。开启权重后,可以为每个记录值设置权重,权重值设置范围为:1-100,根据记录值的权重,通过负载均衡算法返回一个合适的记录值。
-
-说明
-一条规则最多添加 10 个记录值。
-
-TTL
-
-必填,自定义解析记录的有效期。有效期越短,HTTPDNS SDK 中的解析记录缓存过期就越快。同时,HTTPDNS SDK 请求新的解析记录的频率就越高。
-
-