如何在Tapir/http4s中获取未解码含RFC3986保留字符的查询参数?
获取Tapir/http4s中未解码的查询参数
Tapir搭配http4s时,默认会自动对查询参数做URL解码,这就是你遇到%3A被转成:的原因。要获取原始未解码的参数,有两种可行方案:
1. 直接获取原始查询字符串
使用Tapir的rawQueryString端点输入,拿到完整的原始查询串后手动提取目标参数:
import sttp.tapir._ import sttp.tapir.server.http4s.Http4sServerInterpreter // 定义端点,接收原始查询字符串 val rawQueryEndpoint = endpoint.get .in(rawQueryString) .out(stringBody) // 业务逻辑中手动解析提取pairs的原始值 val serverLogic = (rawQuery: String) => { val pairsRawValue = rawQuery .split("&") .find(_.startsWith("pairs=")) .map(_.drop(6)) // 去掉"pairs="前缀 .getOrElse("") // 这里pairsRawValue就是未解码的"1:hello%3Aworld",后续按你的逻辑处理 Right(pairsRawValue) }
2. 自定义参数解码器
通过自定义Codec,让Tapir不对目标参数做解码处理:
import sttp.tapir.Codec import sttp.tapir.CodecFormat.QueryString // 定义不做URL解码的字符串Codec val rawQueryParamCodec: Codec[String, String, QueryString] = Codec.string.mapDecode(identity)(Right(_)) // 使用自定义Codec定义查询参数 val customCodecEndpoint = endpoint.get .in(query(rawQueryParamCodec)("pairs")) .out(stringBody) // 此时serverLogic拿到的pairs参数就是原始未解码值 val serverLogic = (pairsRaw: String) => { Right(pairsRaw.split(":").mkString(",")) }
注意:http4s底层会解析解码后的参数,但rawQueryString会保留请求的原始查询内容,因此第一种方法的可靠性更高。你的临时方案indexOf可以应急,但上面两种方法能从根源解决问题。
内容的提问来源于stack exchange,提问作者FredericS
相关产品推荐
相关产品推荐

