尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Electron ResolvedEndpoint 结构与 resolveHost 主机解析:字段语义、完整参数与源码级实现

Electron ResolvedEndpoint 结构与 resolveHost 主机解析:字段语义、完整参数与源码级实现 Electron ResolvedEndpoint 结构与 resolveHost 主机解析:字段语义、完整参数与源码级实现【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron本文以 Electron 官方 API 文档中的ResolvedEndpoint结构文档为主体,完整解析该结构的字段与取值(含地址族到AF_*常量的映射),说明它在ResolvedHost结果模型中的位置,给出通过net.resolveHost()/ses.resolveHost()获取它的完整参数与用法,并结合仓库中的 C 实现与测试用例验证其真实行为。ResolvedEndpoint 结构:字段与取值ResolvedEndpoint 结构文档定义了一个描述“单个已解析网络端点”的对象,是 Electron 主机解析结果的最小单元。它包含两个字段:字段类型说明addressstring解析得到的 IP 地址字符串(如10.0.0.1、::1)familystring地址族,取以下三个枚举值之一family的枚举值直接对应 POSIX socket 编程中的地址族常量:ipv4— Corresponds toAF_INET;ipv6— Corresponds toAF_INET6;unspec— Corresponds toAF_UNSPEC(地址族未指定)。这种与系统常量一一对应的命名方式意味着:family不是 Electron 自定义的语义标签,而是底层地址解析栈返回的地址族信息在 JS 层的字符串化表达。对开发者最直接的实践意义是——拿到endpoints数组后,可以用family字段判断每个地址是 IPv4 还是 IPv6,从而在双栈(dual-stack)场景下自行选择连接地址,而不必依赖address字符串本身是否包含:来猜测。ResolvedEndpoint 在结果模型中的位置:ResolvedHost 容器ResolvedEndpoint从不单独出现在 API 返回值里,它总是以数组形式内嵌于 ResolvedHost 结构中:ResolvedHost { endpoints: ResolvedEndpoint[] // resolved DNS entries for the hostname }也就是说,一次主机名解析的结果是“一个主机 → 多个端点”的集合。同一个主机名可以同时拥有 A 记录与 AAAA 记录,或者在 DNS/hosts 中配置了多条记录时返回多个ResolvedEndpoint元素;因此消费端应按数组遍历处理,而不是假设只有一个地址。获取方式:net.resolveHost() 与 ses.resolveHost()ResolvedHost(及其内部的ResolvedEndpoint[])由两个 API 以 Promise 形式返回:net.resolveHost(host, [options])— 基于默认会话解析主机;ses.resolveHost(host, [options])— 基于指定Session解析,便于在自定义会话/分区(不同代理、不同 Cookie 与 DNS 配置)下独立解析。两个 API 接受完全相同的options参数,完整参数说明如下(继承自 net.md 与 session.md):hoststring - Hostname to resolve.optionsObject (optional)queryTypestring (optional) - 请求的 DNS 查询类型。未指定时,解析器会根据 IPv4/IPv6 设置自行选择 A 或 AAAA(或两者):A- 仅获取 A 记录;AAAA- 仅获取 AAAA 记录。sourcestring (optional) - 解析地址的来源。默认允许解析器自行选择合适的来源;该选项只影响“大型外部来源”(如调用系统解析、使用 DNS);即使指定了来源,结果仍可能来自缓存、localhost解析或 IP 字面量。取值:any(默认)- 解析器自行选择,结果可能来自 DNS、MulticastDNS、HOSTS 文件等;system- 结果仅来自系统或操作系统,例如通过getaddrinfo()系统调用;dns- 结果仅来自 DNS 查询;mdns- 结果仅来自 Multicast DNS 查询;localOnly- 不使用任何外部来源,结果仅来自不受 source 设置影响的快速本地来源(缓存、hosts 文件、IP 字面量解析等)。cacheUsagestring (optional) - 指示可以使用哪些 DNS 缓存条目提供响应:allowed(默认)- 若未过期,结果可来自主机缓存;staleAllowed- 即使过期(按 TTL 或网络变化)也可使用主机缓存;disallowed- 结果不来自主机缓存。secureDnsPolicystring (optional) - 控制本次请求的 Secure DNS 行为:allow(默认)disable返回值均为PromiseResolvedHost,Promise 以该主机解析出的 IP 地址集合(即endpoints数组)resolve;解析失败时 reject(错误信息为 Chromium 网络错误字符串,如net::ERR_NAME_NOT_RESOLVED)。典型的 main process 用法:const { net, session } require(electron) // 默认会话解析 net.resolveHost(example.com).then(({ endpoints }) { for (const ep of endpoints) { console.log(ep.family, ep.address) // 例如: ipv4 93.184.216.34 / ipv6 2606:2800:220:1:248:1893:25c8:1946 } }) // 只查 AAAA 记录,强制绕开本地缓存 net.resolveHost(example.com, { queryType: AAAA, cacheUsage: disallowed }) .then(({ endpoints }) console.log(endpoints)) .catch((err) console.error(err)) // 例如 net::ERR_NAME_NOT_RESOLVED // 在自定义会话中解析(隔离的代理/DNS 环境) session.fromPartition(persist:resolver-test).resolveHost(example.com) .then(({ endpoints }) console.log(endpoints))源码级实现:从 JS Promise 到 Chromium 主机解析器从源码结构看,ResolvedEndpoint数组的生成链路横跨 JS 封装层与 C 网络层,可以沿以下文件逐层追踪:1. JS 封装层:net 模块只是 Session 的代理lib/browser/api/net.ts 中,net.resolveHost直接委托给默认会话:export function resolveHost(host: string, options?: Electron.ResolveHostOptions): PromiseElectron.ResolvedHost { return session.defaultSession.resolveHost(host, options) }因此net.resolveHost与ses.resolveHost的差异仅在于使用的Session(即ElectronBrowserContext)不同,核心实现只有一份。2. C 入口:Session::ResolveHost 构造 Promise 与端点字典真正的 API 绑定在 shell/browser/api/electron_api_session.cc 的Session::ResolveHost中(方法在 L1818 处通过.SetMethod(resolveHost, Session::ResolveHost)注册)。其关键逻辑:创建gin_helper::Promisegin_helper::Dictionary,并构造一个引用计数的ResolveHostFunction承载本次解析请求;回调中先判断网络错误码:若net_error 0,则以net::ErrorToString(net_error)作为错误信息 reject —— 这就是文档中“解析失败被 reject 且错误信息形如net::ERR_NAME_NOT_RESOLVED”的来源;成功分支中,从 Chromium 的net::AddressList取出addrs-endpoints(),写入 JS 字典的endpoints键后 resolve:dict.Set(endpoints, addrs-endpoints()); promise.Resolve(dict);net::AddressList内部的端点集合经 gin 转换器映射为 JS 对象数组,每个对象即一个ResolvedEndpoint,其address与family字段分别对应端点的 IP 地址与地址族——这正是结构文档中family取值能对应AF_INET/AF_INET6/AF_UNSPEC的底层原因。3. 解析请求的跨进程传递:ResolveHostFunctionshell/browser/net/resolve_host_function.cc(头文件见 resolve_host_function.h)通过 mojo 接口network::mojom::ResolveHostClient向 Chromium 网络服务发起解析。从源码结构看有几个值得注意的细节:Run()中构造net::HostPortPair(host_, 0)(端口为 0,表明只关心主机解析),并绑定一个 mojo receiver;断连即视为解析失败:receiver 的set_disconnect_handler会调用OnComplete并传入net::ERR_NAME_NOT_RESOLVED与空的AddressList(见 L53-L57)——这解释了为什么测试中“查不到记录”会稳定得到ERR_NAME_NOT_RESOLVED错误;进程路径区分(L58-L72):在 utility process 中通过URLLoaderBundle::GetInstance()-GetHostResolver()发起解析;在浏览器进程中则要求当前处于 UI 线程,走browser_context_-GetDefaultStoragePartition()-GetNetworkContext()-ResolveHost(...)。也就是说,该 API 在主进程与 utility process 中均可用,只是底层的 HostResolver 获取路径不同;OnComplete在回调前显式receiver_.reset()并持有scoped_refptr自引用(见 L75-L88),以保证Reset过程中对象不被提前销毁,最后只把resolve_error_info.error与resolved_addresses传给上层回调。测试验证:family 与 address 的真实断言仓库自带测试对ResolvedEndpoint两个字段的取值给出了可复现的验证依据。spec/api-net-spec.ts 中net.resolveHost用例:test(resolves ipv4.localhost2, async () { const { endpoints } await net.resolveHost(ipv4.localhost2) expect(endpoints).to.be.a(array) expect(endpoints).to.have.lengthOf(1) expect(endpoints[0].family).to.equal(ipv4) expect(endpoints[0].address).to.equal(10.0.0.1) })同组测试还断言:ipv6.localhost2解析后endpoints[0].family为ipv6、address为::1;对纯 IPv4 主机请求queryType: AAAA(或对纯 IPv6 主机请求queryType: A)、以及解析不存在的notfound.localhost2,都会以/net::ERR_NAME_NOT_RESOLVED/被 reject。spec/api-session-spec.ts 中对ses.resolveHost(host)存在完全平行的用例组,验证了 Session 级 API 与net级 API 返回相同的ResolvedHost/ResolvedEndpoint形态。这些测试直接印证了结构文档的语义:endpoints是数组,每个元素的family为小写枚举字符串ipv4/ipv6(对应文档中的AF_INET/AF_INET6族),address为点分或冒号记法 IP 字符串。实践要点小结按数组消费:endpoints是ResolvedEndpoint[],双栈或一主多名记录会返回多个元素;结合queryType选项(如{ queryType: AAAA })可在解析端就过滤出单一地址族。用 family 而非字符串解析判断地址族:family与AF_INET/AF_INET6/AF_UNSPEC一一对应,是判断ipv4/ipv6/unspec的可靠依据;unspec表示地址族未指定。选择解析来源与缓存策略:source控制结果来自 DNS、系统(getaddrinfo())、mDNS 还是仅本地来源;cacheUsage控制是否允许使用主机缓存(含staleAllowed允许过期缓存),排查 DNS 相关问题时可组合source: dns与cacheUsage: disallowed强制走实时 DNS 查询。会话隔离:net.resolveHost固定使用默认会话;需要不同代理/DNS 环境时,使用ses.resolveHost在对应Session上解析,两者共享同一份 C 实现,仅ElectronBrowserContext不同。失败即 reject:解析失败(含网络服务 mojo 管道断连)统一以net::ERR_NAME_NOT_RESOLVED等 Chromium 网络错误字符串 reject,调用方应始终写catch分支。【免费下载链接】electron:electron: Build cross-platform desktop apps with JavaScript, HTML, and CSS项目地址: https://gitcode.com/GitHub_Trending/el/electron创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表