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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:24:59