You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala语言如何使用Akka HTTP查询及管理A、SRV类型DNS记录

DNS记录类型区分及Akka HTTP查询SRV记录实现方案

A记录与SRV记录的核心区别

  • A记录:是地址解析记录,直接将域名映射到对应的IPv4地址,你之前用的InetAddress.getAllByName本质就是查询A记录,所以只能拿到IP列表,无法识别其他类型的DNS记录
  • SRV记录:是服务定位记录,除了对应服务域名外,还会返回服务的优先级、权重、端口号,专门用于定位特定协议/端口的服务,格式为_服务名._协议名.域名,你给出的示例_thrift._tcp.prova.geo.server.com.就是标准的SRV记录格式

基于Scala + Akka HTTP的SRV记录查询实现

首先确保你的项目引入了对应版本的Akka IO依赖,sbt配置参考如下:

// 版本号需和项目现有Akka版本保持一致
libraryDependencies += "com.typesafe.akka" %% "akka-io" % "2.8.5"

完整实现代码示例:

import akka.actor.ActorSystem
import akka.io.dns.{ARecord, DnsProtocol, SRVRecord}
import akka.io.{Dns, IO}
import akka.pattern.ask
import akka.util.Timeout

import scala.concurrent.Future
import scala.concurrent.duration._

// 定义SRV查询结果结构,方便业务侧使用
case class SrvTarget(priority: Int, weight: Int, port: Int, targetDomain: String, ipList: List[String])

class SrvDnsManager(implicit actorSystem: ActorSystem) {
  // 配置DNS查询超时时间
  private implicit val queryTimeout: Timeout = 3.seconds
  private val dnsActor = IO(Dns)(actorSystem)
  import actorSystem.dispatcher

  /**
   * 查询指定SRV域名的记录,同时自动解析目标域名的A记录
   * @param srvDomain 待查询的SRV域名,例如:_thrift._tcp.prova.geo.server.com
   * @return 解析完成的SRV目标列表异步结果
   */
  def getSrvRecords(srvDomain: String): Future[List[SrvTarget]] = {
    // 发起指定类型为SRV的DNS查询请求
    val srvQuery = (dnsActor ? DnsProtocol.Resolve(srvDomain, DnsProtocol.SRV)).mapTo[DnsProtocol.Resolved]

    srvQuery.flatMap { resolvedResult =>
      // 过滤提取所有SRV记录
      val srvRecords = resolvedResult.records.collect { case record: SRVRecord => record }

      // 批量查询每个SRV记录对应目标域名的IP地址
      val targetResultFutures = srvRecords.map { srvRecord =>
        val ipQuery = (dnsActor ? DnsProtocol.Resolve(srvRecord.target)).mapTo[DnsProtocol.Resolved]
        ipQuery.map { ipRes =>
          val ips = ipRes.records.collect { case aRecord: ARecord => aRecord.ip.getHostAddress }.toList
          SrvTarget(
            priority = srvRecord.priority,
            weight = srvRecord.weight,
            port = srvRecord.port,
            targetDomain = srvRecord.target,
            ipList = ips
          )
        }
      }

      Future.sequence(targetResultFutures.toList)
    }
  }
}

// 调用示例
object SrvQueryDemo extends App {
  implicit val system: ActorSystem = ActorSystem("SrvQuerySystem")
  val srvManager = new SrvDnsManager()

  val testSrvDomain = "_thrift._tcp.prova.geo.server.com"
  srvManager.getSrvRecords(testSrvDomain).map { records =>
    println(s"共查询到${records.size}条SRV记录:")
    records.foreach { record =>
      println(s"优先级:${record.priority} 权重:${record.weight} 端口:${record.port} 域名:${record.targetDomain} IP列表:${record.ipList.mkString(",")}")
    }
  }.recover {
    case e: Exception => println(s"SRV记录查询失败:${e.getMessage}")
  }
}

注意事项

  • InetAddress.getAllByName系统方法默认仅支持查询A/AAAA记录,不支持SRV等其他DNS记录类型,这是原有代码无法获取SRV记录的根本原因
  • Akka DNS默认使用系统配置的DNS服务器,可通过Akka配置项akka.io.dns.resolver自定义指定DNS服务器地址
  • 生产环境使用建议添加查询结果本地缓存,避免频繁发起DNS请求影响性能

内容的提问来源于stack exchange,提问作者Riccardo Califano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 03:06:00