Scala中如何定义支持任意Case Class的Sttp通用Get请求方法
解决Scala Sttp通用Get请求的任意Case Class响应映射问题
你不需要通过传入responseClass参数来实现动态解析,Scala的泛型+类型类机制可以安全、优雅地处理任意case class的JSON响应映射,完全契合Sttp的设计思路。以下是具体实现方案:
核心思路
Sttp的asJson[T]依赖JSON库(比如常用的Circe)提供的Decoder[T]类型类,只要你的case class有对应的解码器,编译器就能自动推导解析逻辑,无需手动传递类对象。
完整实现代码
import sttp.client3._ import sttp.model.Uri import io.circe.{Decoder, HttpErrorInfo} import io.circe.generic.semiauto._ // 假设使用Circe作为JSON解析库,需提前添加对应依赖 def getRequest[T]( baseUri: String, queryString: String, trackingId: String, component: String = "http-v2-client-get-request", numberOfRetries: Int = 0 )(implicit decoder: Decoder[T], backend: SttpBackend[Identity, Any]): Either[HttpErrorInfo, T] = { // 安全构建带查询参数的URI val fullUri = Uri.parse(baseUri).getOrElse(Uri.empty).addQueryString(queryString) val request = basicRequest .get(fullUri) .header("Tracking-Id", trackingId) // 示例:将trackingId放入请求头 .response(asJson[T]) // 用泛型T替代硬编码类 // 实现重试逻辑 val retryableRequest = if (numberOfRetries > 0) { request.retryWhen(_.isServerError, maxRetries = numberOfRetries) } else { request } // 发送请求并返回结果 retryableRequest.send(backend).body }
关键修改点说明
泛型参数
T:- 方法定义添加
[T]泛型,替代原有的responseClass参数 - 返回类型改为
Either[HttpErrorInfo, T],让编译器自动适配目标类型
- 方法定义添加
隐式类型类参数:
implicit decoder: Decoder[T]:要求调用方提供目标case class的Circe解码器(可通过deriveDecoder自动生成)implicit backend: SttpBackend[Identity, Any]:Sttp需要后端实例发送请求(比如HttpURLConnectionBackend())
URI与查询参数处理:
- 用
Uri.parse和addQueryString安全拼接查询参数,避免手动字符串拼接的错误
- 用
重试逻辑:
- 通过
retryWhen实现服务器错误时的重试,直接复用Sttp内置的重试机制
- 通过
使用示例
// 1. 定义目标case class case class User(id: Int, name: String, email: String) // 2. 自动生成Circe解码器 implicit val userDecoder: Decoder[User] = deriveDecoder[User] // 3. 初始化Sttp后端 implicit val backend: SttpBackend[Identity, Any] = HttpURLConnectionBackend() // 4. 调用通用Get方法,编译器自动推导T为User类型 val result: Either[HttpErrorInfo, User] = getRequest( baseUri = "https://api.example.com/users/1", queryString = "include=email", trackingId = "abc-123", numberOfRetries = 2 ) // 处理结果 result match { case Right(user) => println(s"获取用户成功:$user") case Left(error) => println(s"请求失败:${error.message}") }
为什么不用动态类对象?
Scala是静态类型语言,泛型+类型类的方式在编译时就能检查类型匹配和解析逻辑,比动态反射更安全、性能更好,也更符合Scala的编程范式。
内容的提问来源于stack exchange,提问作者vukojevicf
相关产品推荐
相关产品推荐

