WebClient 编码 queryParams spring

Posted

技术标签:

【中文标题】WebClient 编码 queryParams spring【英文标题】:WebClient encoding queryParams spring 【发布时间】:2022-01-01 00:14:46 【问题描述】:

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

其中一个 queryParams 值为:

[  "var": "report_days", "op": "=", "val": "7"  ]

它是从 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。 所以解码到MultiMap<String, String>是正确执行的,但是在uriBuilder会抛出异常。

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

例外:

java.lang.IllegalArgumentException: Not enough variable values available to expand '"var"'
2021-11-22T11:17:38.252421700Z  at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:370)
2021-11-22T11:17:38.252461800Z  Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
2021-11-22T11:17:38.252492300Z Error has been observed at the following site(s):
2021-11-22T11:17:38.252521200Z  *__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter [DefaultWebFilterChain]
2021-11-22T11:17:38.252586100Z  *__checkpoint ⇢ 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]
2021-11-22T11:17:38.252628200Z Stack trace:
2021-11-22T11:17:38.252666300Z      at org.springframework.web.util.UriComponents$VarArgsTemplateVariables.getValue(UriComponents.java:370)
2021-11-22T11:17:38.252699800Z      at org.springframework.web.util.HierarchicalUriComponents$QueryUriTemplateVariables.getValue(HierarchicalUriComponents.java:1087)
2021-11-22T11:17:38.252723100Z      at org.springframework.web.util.UriComponents.expandUriComponent(UriComponents.java:263)
2021-11-22T11:17:38.252738600Z      at org.springframework.web.util.HierarchicalUriComponents.lambda$expandQueryParams$5(HierarchicalUriComponents.java:450)
2021-11-22T11:17:38.252754400Z      at java.base/java.util.Map.forEach(Map.java:713)

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

return webClient.get()
  .uri(uriBuilder -> uriBuilder.path("/nodes/last").queryParam(URLEncoder.encode(queryParams.getFirst("filter"), StandardCharsets.UTF_8)).build())

【问题讨论】:

您的堆栈跟踪与您在问题中的代码不对应。 “/nodeNew/all/last_protected”不是“/nodes/last”。请提供一个可重现的测试用例,其中包含显示行为的代码。 您好,stackTrace 是正确的。这是网关服务。该请求在 GET "/nodeNew/all/last_protected" 上,然后在 RouterFunction 我有一个处理该请求的处理程序,WebClient 对几个微服务执行 GET 并合并来自它们的响应。此 webClient 执行来自处理程序的请求之一 【参考方案1】:

我最近遇到了同样的麻烦,这确实有效:

使用自定义 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();

然后在客户端方法中:

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

警察局。对不起我的英语不好。

【讨论】:

以上是关于WebClient 编码 queryParams spring的主要内容,如果未能解决你的问题,请参考以下文章

WebClient 数据传输

使用WebClient下载网页,用正则匹配需要的内容

Vert.x WebClient WebClientOptions

何时使用 @QueryParam 与 @PathParam

如何将值设置为可选的 QueryParam 以在 java 中调用 rest api

Angular Test Jest - TypeError:无法读取未定义的属性“queryParams”