From 4d275c921d9cc03370e3ba4e4f2d433aa46a153e Mon Sep 17 00:00:00 2001 From: robin Date: Tue, 24 Feb 2026 22:43:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=89=8D=E7=AB=AF=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../httpdns/apps/appSettingsResetAESSecret.go | 23 -- .../default/httpdns/apps/appSettings_store.go | 32 --- .../web/actions/default/httpdns/apps/init.go | 1 - .../httpdns/clusters/clusterSettings.go | 5 +- .../actions/default/httpdns/sandbox/index.go | 27 +- .../actions/default/httpdns/sandbox/test.go | 16 +- .../@default/httpdns/apps/appSettings.html | 20 +- .../@default/httpdns/apps/appSettings.js | 19 +- .../@default/httpdns/apps/customRecords.js | 8 +- .../apps/customRecordsCreatePopup.html | 249 +++++++++-------- .../views/@default/httpdns/apps/index.html | 6 +- .../views/@default/httpdns/guide/index.html | 8 - .../web/views/@default/httpdns/guide/index.js | 2 - .../views/@default/httpdns/sandbox/index.html | 20 +- .../views/@default/httpdns/sandbox/index.js | 59 +++- EdgeHttpDNS/HTTPDNS主计划-V1.2.md | 233 ++++++++-------- EdgeHttpDNS/HTTPDNS后端开发计划.md | 254 ++++++++++++++++++ EdgeHttpDNS/自定义解析功能.md | 114 -------- 18 files changed, 611 insertions(+), 485 deletions(-) delete mode 100644 EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettingsResetAESSecret.go create mode 100644 EdgeHttpDNS/HTTPDNS后端开发计划.md delete mode 100644 EdgeHttpDNS/自定义解析功能.md diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettingsResetAESSecret.go b/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettingsResetAESSecret.go deleted file mode 100644 index c3a75e2..0000000 --- a/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettingsResetAESSecret.go +++ /dev/null @@ -1,23 +0,0 @@ -package apps - -import ( - "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" - "github.com/iwind/TeaGo/actions" -) - -type AppSettingsResetAESSecretAction struct { - actionutils.ParentAction -} - -func (this *AppSettingsResetAESSecretAction) RunPost(params struct { - AppId int64 - - Must *actions.Must - CSRF *actionutils.CSRF -}) { - params.Must.Field("appId", params.AppId).Gt(0, "请选择应用") - - app := pickApp(params.AppId) - resetAESSecret(app) - this.Success() -} diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettings_store.go b/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettings_store.go index 6026936..4c327a2 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettings_store.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/apps/appSettings_store.go @@ -17,7 +17,6 @@ var appSettingsStore = struct { func defaultAppSettings(app maps.Map) maps.Map { signSecretPlain := randomPlainSecret("ss") - aesSecretPlain := randomPlainSecret("as") return maps.Map{ "appId": app.GetString("appId"), "primaryClusterId": app.GetInt64("clusterId"), @@ -25,9 +24,6 @@ func defaultAppSettings(app maps.Map) maps.Map { "signSecretPlain": signSecretPlain, "signSecretMasked": maskSecret(signSecretPlain), "signSecretUpdatedAt": "2026-02-20 12:30:00", - "aesSecretPlain": aesSecretPlain, - "aesSecretMasked": maskSecret(aesSecretPlain), - "aesSecretUpdatedAt": "2026-02-12 09:45:00", "appStatus": app.GetBool("isOn"), "defaultTTL": 30, "fallbackTimeoutMs": 300, @@ -52,9 +48,6 @@ func cloneSettings(settings maps.Map) maps.Map { "signSecretPlain": settings.GetString("signSecretPlain"), "signSecretMasked": settings.GetString("signSecretMasked"), "signSecretUpdatedAt": settings.GetString("signSecretUpdatedAt"), - "aesSecretPlain": settings.GetString("aesSecretPlain"), - "aesSecretMasked": settings.GetString("aesSecretMasked"), - "aesSecretUpdatedAt": settings.GetString("aesSecretUpdatedAt"), "appStatus": settings.GetBool("appStatus"), "defaultTTL": settings.GetInt("defaultTTL"), "fallbackTimeoutMs": settings.GetInt("fallbackTimeoutMs"), @@ -110,16 +103,6 @@ func resetSignSecret(app maps.Map) maps.Map { return settings } -func resetAESSecret(app maps.Map) maps.Map { - settings := loadAppSettings(app) - aesSecretPlain := randomPlainSecret("as") - settings["aesSecretPlain"] = aesSecretPlain - settings["aesSecretMasked"] = maskSecret(aesSecretPlain) - settings["aesSecretUpdatedAt"] = nowDateTime() - saveAppSettings(app.GetInt64("id"), settings) - return settings -} - func nowDateTime() string { return time.Now().Format("2006-01-02 15:04:05") } @@ -182,21 +165,6 @@ func ensureSettingsFields(settings maps.Map) bool { changed = true } - aesSecretPlain := settings.GetString("aesSecretPlain") - if len(aesSecretPlain) == 0 { - aesSecretPlain = randomPlainSecret("as") - settings["aesSecretPlain"] = aesSecretPlain - changed = true - } - if len(settings.GetString("aesSecretMasked")) == 0 { - settings["aesSecretMasked"] = maskSecret(aesSecretPlain) - changed = true - } - if len(settings.GetString("aesSecretUpdatedAt")) == 0 { - settings["aesSecretUpdatedAt"] = nowDateTime() - changed = true - } - if len(settings.GetString("sniPolicy")) == 0 { settings["sniPolicy"] = "level2" changed = true diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/apps/init.go b/EdgeAdmin/internal/web/actions/default/httpdns/apps/init.go index 152b4c9..d9db84b 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/apps/init.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/apps/init.go @@ -19,7 +19,6 @@ func init() { GetPost("/app/settings", new(AppSettingsAction)). Post("/app/settings/toggleSignEnabled", new(AppSettingsToggleSignEnabledAction)). Post("/app/settings/resetSignSecret", new(AppSettingsResetSignSecretAction)). - Post("/app/settings/resetAESSecret", new(AppSettingsResetAESSecretAction)). Get("/domains", new(DomainsAction)). Get("/customRecords", new(CustomRecordsAction)). GetPost("/createPopup", new(CreatePopupAction)). diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go b/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go index 21c1223..9c87642 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/clusters/clusterSettings.go @@ -45,7 +45,7 @@ func (this *ClusterSettingsAction) RunGet(params struct { cid := strconv.FormatInt(params.ClusterId, 10) this.Data["leftMenuItems"] = []map[string]interface{}{ {"name": "基础设置", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=basic", "isActive": section == "basic"}, - {"name": "TLS", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=tls", "isActive": section == "tls"}, + {"name": "端口设置", "url": "/httpdns/clusters/cluster/settings?clusterId=" + cid + "§ion=tls", "isActive": section == "tls"}, } settings["isDefaultCluster"] = (policies.LoadDefaultClusterID() == cluster.GetInt64("id")) @@ -88,7 +88,8 @@ func (this *ClusterSettingsAction) RunGet(params struct { } } else { sslPolicy = &sslconfigs.SSLPolicy{ - IsOn: true, + IsOn: true, + MinVersion: "TLS 1.1", } } diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/index.go b/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/index.go index 62049e1..4109d16 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/index.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/index.go @@ -3,6 +3,7 @@ package sandbox import ( "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies" ) type IndexAction struct { @@ -15,21 +16,29 @@ func (this *IndexAction) Init() { func (this *IndexAction) RunGet(params struct{}) { httpdnsutils.AddLeftMenu(this.Parent()) + + this.Data["clusters"] = policies.LoadAvailableDeployClusters() this.Data["apps"] = []map[string]interface{}{ { - "id": int64(1), - "name": "主站移动业务", - "appId": "ab12xc34s2", + "id": int64(1), + "name": "主站移动业务", + "appId": "ab12xc34s2", + "clusterId": int64(1), + "domains": []string{"api.business.com", "www.aliyun.com"}, }, { - "id": int64(2), - "name": "视频网关业务", - "appId": "vd8992ksm1", + "id": int64(2), + "name": "支付网关业务", + "appId": "vd8992ksm1", + "clusterId": int64(2), + "domains": []string{"payment.business.com"}, }, { - "id": int64(3), - "name": "海外灰度测试", - "appId": "ov7711hkq9", + "id": int64(3), + "name": "海外灰度测试", + "appId": "ov7711hkq9", + "clusterId": int64(1), + "domains": []string{"global.example.com", "edge.example.com"}, }, } this.Show() diff --git a/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/test.go b/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/test.go index e234028..24117ea 100644 --- a/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/test.go +++ b/EdgeAdmin/internal/web/actions/default/httpdns/sandbox/test.go @@ -6,6 +6,7 @@ import ( "strconv" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils" + "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/policies" "github.com/iwind/TeaGo/maps" ) @@ -14,10 +15,11 @@ type TestAction struct { } func (this *TestAction) RunPost(params struct { - AppId string - Domain string - ClientIp string - Qtype string + AppId string + ClusterId int64 + Domain string + ClientIp string + Qtype string }) { if len(params.ClientIp) == 0 { params.ClientIp = "203.0.113.100" @@ -40,7 +42,11 @@ func (this *TestAction) RunPost(params struct { query.Set("dn", params.Domain) query.Set("cip", params.ClientIp) query.Set("qtype", params.Qtype) - requestURL := "https://api.httpdns.example.com/resolve?" + query.Encode() + clusterServiceDomain := policies.LoadClusterGatewayByID(params.ClusterId) + if len(clusterServiceDomain) == 0 { + clusterServiceDomain = "gw.httpdns.example.com" + } + requestURL := "https://" + clusterServiceDomain + "/resolve?" + query.Encode() this.Data["result"] = maps.Map{ "code": 0, diff --git a/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.html b/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.html index ae8e38d..5e3718f 100644 --- a/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.html +++ b/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.html @@ -116,26 +116,8 @@

用于生成鉴权接口的安全密钥。

- - 数据加密 Secret - -
- {{aesSecretVisible ? settings.aesSecretPlain : settings.aesSecretMasked}} - - - -
-

最近更新:{{settings.aesSecretUpdatedAt}}

-

用于解析接口数据加密的密钥。

- - - \ No newline at end of file + diff --git a/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.js b/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.js index d065aad..1f5d8f6 100644 --- a/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.js +++ b/EdgeAdmin/web/views/@default/httpdns/apps/appSettings.js @@ -2,14 +2,13 @@ Tea.context(function () { this.activeSection = this.activeSection || "basic"; this.success = NotifyReloadSuccess("保存成功"); this.signSecretVisible = false; - this.aesSecretVisible = false; this.toggleSignEnabled = function () { let that = this; let targetIsOn = !this.settings.signEnabled; if (targetIsOn) { - teaweb.confirm("html:开启后,服务端会对解析请求进行签名鉴权,未签名、签名无效或过期的请求都解析失败,确认开启吗?", function () { + teaweb.confirm("html:开启后,服务端会对解析请求进行签名鉴权,未签名、签名无效或过期的请求都会解析失败,确认开启吗?", function () { that.$post("/httpdns/apps/app/settings/toggleSignEnabled") .params({ appId: that.app.id, @@ -93,20 +92,4 @@ Tea.context(function () { }); }); }; - - this.resetAESSecret = function () { - let that = this; - teaweb.confirm("确定要重置 AES Secret 吗?", function () { - that.$post("/httpdns/apps/app/settings/resetAESSecret") - .params({ - appId: that.app.id - }) - .success(function () { - teaweb.success("AES Secret 已重置", function () { - teaweb.reload(); - }); - }); - }); - }; }); - diff --git a/EdgeAdmin/web/views/@default/httpdns/apps/customRecords.js b/EdgeAdmin/web/views/@default/httpdns/apps/customRecords.js index a55e8a5..aee143c 100644 --- a/EdgeAdmin/web/views/@default/httpdns/apps/customRecords.js +++ b/EdgeAdmin/web/views/@default/httpdns/apps/customRecords.js @@ -8,8 +8,8 @@ return; } teaweb.popup("/httpdns/apps/customRecords/createPopup?appId=" + this.app.id + "&domainId=" + this.domain.id, { - width: "56em", - height: "40em", + width: "42em", + height: "33em", title: "新增自定义解析规则" }); }; @@ -19,8 +19,8 @@ return; } teaweb.popup("/httpdns/apps/customRecords/createPopup?appId=" + this.app.id + "&domainId=" + this.domain.id + "&recordId=" + recordId, { - width: "56em", - height: "40em", + width: "42em", + height: "33em", title: "编辑自定义解析规则" }); }; diff --git a/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.html b/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.html index 42cd121..68b8a6d 100644 --- a/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.html +++ b/EdgeAdmin/web/views/@default/httpdns/apps/customRecordsCreatePopup.html @@ -1,32 +1,37 @@ {$layout "layout_popup"}

编辑自定义解析规则

@@ -40,98 +45,116 @@ - - - - - - - - - - - -
域名 *{{record.domain}}
规则名称 * - -

例如:上海电信灰度-v2。

-
线路 -
- + + + + + + + + + + + + + - - - - + + + + - - - - - - - - - +
+ + 添加记录值 + + {{recordItems.length}}/10 +
+ + + + + + + + + + +
域名 *{{record.domain}}
规则名称 * + +

例如:上海电信灰度-v2。

+
线路 +
+ + + + - - - - - - -
-
解析记录值 * -
-
- - -
-
-
-
- + + +
-
- +
解析记录值 * +
+
+ + +
-
- + +
+
+ +
+
+ +
+
+ +
+
+ +
- -
-
- - 添加记录值 - - {{recordItems.length}}/10 -
-

开启后每条记录可配置权重,范围 1-100。

-
TTL * -
- - -
-
规则状态 -
- - -
-
TTL * +
+ + +
+
状态 +
+ + +
+
- + \ 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 @@
- +
-

解析配置

+

解析测试

-
+
+ + +
- +
@@ -134,4 +144,4 @@
-
\ 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 请求新的解析记录的频率就越高。 - -