WebClient编码queryParams spring

kam*_*uti 3 spring spring-mvc spring-boot spring-webflux

当一个参数的值被解码为字符串的 JSON 值时,我在 WebClient 编码查询参数时遇到问题。

\n

queryParams 值之一是:

\n
[ { "var": "report_days", "op": "=", "val": "7" } ]\n
Run Code Online (Sandbox Code Playgroud)\n

它是从 HTTP 方法解码的: ? filter=%5B%7B%22var%22%3A%22report_days%22%2C%22op%22%3A%22%3D%22%2C%22val%22%3A%227%22%7D%5D.\n因此解码到MultiMap<String, String>正确执行,但在uriBuilder抛出异常。

\n
[ { "var": "report_days", "op": "=", "val": "7" } ]\n
Run Code Online (Sandbox Code Playgroud)\n

例外:

\n
java.lang.IllegalArgumentException: Not enough variable values available to expand \'"var"\'\n2021-11-22T11:17:38.252421700Z  at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:370)\n2021-11-22T11:17:38.252461800Z  Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: \n2021-11-22T11:17:38.252492300Z Error has been observed at the following site(s):\n2021-11-22T11:17:38.252521200Z  *__checkpoint \xc3\xa2\xe2\x80\xa1\xc2\xa2 org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]\n2021-11-22T11:17:38.252586100Z  *__checkpoint \xc3\xa2\xe2\x80\xa1\xc2\xa2 HTTP GET "/nodeNew/all/last_protected?filter=%5B%7B%22var%22%3A%22report_days%22%2C%22op%22%3A%22%3D%22%2C%22val%22%3A%227%22%7D%5D" [ExceptionHandlingWebHandler]\n2021-11-22T11:17:38.252628200Z Stack trace:\n2021-11-22T11:17:38.252666300Z      at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:370)\n2021-11-22T11:17:38.252699800Z      at org.springframework.web.util.HierarchicalUriComponents$QueryUriTemplateVariables.getValue(HierarchicalUriComponents.java:1087)\n2021-11-22T11:17:38.252723100Z      at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:263)\n2021-11-22T11:17:38.252738600Z      at org.springframework.web.util.HierarchicalUriComponents.lambda$expandQueryParams$5(HierarchicalUriComponents.java:450)\n2021-11-22T11:17:38.252754400Z      at java.base/java.util.Map.forEach(Map.java:713)\n
Run Code Online (Sandbox Code Playgroud)\n

也许是一些配置可以解决它?在 queryParams 中可能是另一个值,但不是 JSON 格式,所以我想避免以这种方式执行此操作(现在可以使用,但它必须转发所有 queryParams 而不仅仅是键“过滤器”):

\n
return webClient.get()\n  .uri(uriBuilder -> uriBuilder.path("/nodes/last").queryParams(queryParams).build()) //Problem\n  .header(HttpHeaders.AUTHORIZATION, token)\n  .accept(MediaType.APPLICATION_JSON)\n  .retrieve()\n  .bodyToMono(String.class)\n  .log();\n
Run Code Online (Sandbox Code Playgroud)\n

小智 6

我最近遇到了同样的麻烦,这完成了工作:

  • 创建一个方法,返回带有自定义 DefaultUriBuilderFactory 的 webclient 副本
public WebClient getWebclientNoEncoded() {
    DefaultUriBuilderFactory factory = new DefaultUriBuilderFactory(this.baseUrl); //Here comes your base url
    factory.setEncodingMode(DefaultUriBuilderFactory.EncodingMode.NONE);
    return this.webClient.mutate()
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .uriBuilderFactory(factory)
        .build();
}
Run Code Online (Sandbox Code Playgroud)

然后在客户端方法中:

apiClient.getWebclientNoEncoded()
            .get()
            .uri(uriBuilder -> uriBuilder
                .path("/foo")
                .queryParam(UriUtils.encodeQueryParam(myJsonString, StandardCharsets.UTF_8.toString()))
                .build())
            .header(HttpHeaders.AUTHORIZATION, bearerToken)
            .retrieve()
Run Code Online (Sandbox Code Playgroud)

PD。抱歉我的英语不好。