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

WireMock存根中捕获Query Param并返回的Kotlin实现问题

问题分析

你的代码失效主要有两个核心原因:

  1. urlPathMatching仅匹配URL的路径部分(即/v1/money),不包含查询参数;且你写的/v1/money?accounts=.*里的?是正则特殊字符,会导致路径匹配失败。
  2. 直接在okJson的静态字符串模板中调用Kotlin函数accountsList是无效的——WireMock无法识别这种自定义动态调用,必须用它支持的模板机制或动态响应生成方式。

可行实现方式

方式一:WireMock内置响应模板(推荐,简洁)

WireMock自带响应模板功能,可直接在响应中处理查询参数,无需额外写Kotlin工具函数。
首先确保启用模板扩展:

val portalWiremock = WireMockServer(options().extensions(ResponseTemplateTransformer(true)))
portalWiremock.start()

然后编写存根:

portalWiremock.stubFor(
    get(urlPathEqualTo("/v1/money"))
        .withQueryParam("accounts", matching(".*")) // 可选:限制请求必须携带accounts参数
        .willReturn(
            okJson(
                """
                {
                    "trackingId": "abcde12345",
                    "accounts": [{{split request.query.accounts ',' | arrayMap '{{jsonEscape it}}' | join ','}}]
                }
                """.trimIndent()
            ).withTransformers("response-template")
        )
)

模板语法说明:

  • split request.query.accounts ',':将accounts参数按逗号分割为数组
  • arrayMap '{{jsonEscape it}}':为每个元素添加引号并转义特殊字符
  • join ',':拼接数组元素,配合外层[]生成合法JSON数组

方式二:Kotlin动态生成响应体

如果不想用WireMock模板,可直接通过函数动态构建响应内容:

portalWiremock.stubFor(
    get(urlPathEqualTo("/v1/money"))
        .willReturn(
            aResponse()
                .withStatus(200)
                .withHeader("Content-Type", "application/json")
                .withBody { request ->
                    val accountsParam = request.queryParameter("accounts").firstValue()
                    val accounts = accountsParam?.split(",") ?: emptyList()
                    val accountsJson = accounts.joinToString(",", "[", "]") { "\"$it\"" }
                    """
                    {
                        "trackingId": "abcde12345",
                        "accounts": $accountsJson
                    }
                    """.trimIndent()
                }
        )
)

这种方式完全用Kotlin代码处理参数,灵活度高,适合复杂的自定义逻辑。

方式三:自定义WireMock转换器(复用场景)

如果多个存根都需要处理类似的逗号分隔参数转JSON数组逻辑,可写一个自定义转换器:

class AccountsParamTransformer : ResponseTransformer() {
    override fun transform(request: Request, response: ResponseDefinition, files: FileSource, parameters: Parameters): ResponseDefinition {
        val accountsParam = request.queryParameter("accounts").firstValue()
        val accounts = accountsParam?.split(",") ?: emptyList()
        val accountsJson = accounts.joinToString(",", "[", "]") { "\"$it\"" }
        val modifiedBody = response.bodyAsString.replace("{{accountsList}}", accountsJson)
        return response.copy(body = modifiedBody)
    }

    override fun getName() = "accounts-param-transformer"
}

启用并使用:

val portalWiremock = WireMockServer(options().extensions(AccountsParamTransformer()))
portalWiremock.start()

portalWiremock.stubFor(
    get(urlPathEqualTo("/v1/money"))
        .willReturn(
            okJson(
                """
                {
                    "trackingId": "abcde12345",
                    "accounts": {{accountsList}}
                }
                """.trimIndent()
            ).withTransformers("accounts-param-transformer")
        )
)

关于捕获并返回查询参数的通用性

这种思路完全通用可行,是Mock场景中非常常见的需求(根据请求参数动态生成响应)。你之前的问题只是API使用方式错误,而非思路本身有问题,只要遵循WireMock的规则实现,就能稳定生效。

内容的提问来源于stack exchange,提问作者Maksym Rybalkin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:02:49