【问题标题】:UriComponentsBuilder cannot encode ISO-8601 date parametersUriComponentsBuilder 无法编码 ISO-8601 日期参数
【发布时间】:2020-07-08 21:31:13
【问题描述】:

我在进行一些集成测试时遇到了一个有趣的问题。

我有一个休息端点,它有一些查询参数,这些参数是 ISO-8601 中指定的时间戳(例如:2020-07-08T23:54:36.931159+03:00)。 日期使用 java.time.format.DateTimeFormatter.ISO_OFFSET_DATE_TIME

进行格式化

我使用以下方法创建请求地址:

//Query params are supplied in a Map<String,String>
String baseURL="http://localhost:" + this.port + uri
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL);
    if (params != null) {
      for (final Entry<String, String> entry : params.entrySet()) {
        builder.queryParam(entry.getKey(), entry.getValue());
      }
    }

这将生成以下地址:

http://localhost:8090/remainingAddress?fromDate=2020-07-08T23:54:36.834869+03:00&toDate=2020-07-08T23:54:36.931159+03:00

问题是“+”号没有被编码并保持原来在地图中的样子。在接收端,参数被解码,从而导致以下日期“020-07-08T23:54:36.834869 03:00”(注意空格而不是+),因此当我尝试使用解析日期时相同的格式化程序失败了。

在将值添加到构建器之前,我尝试使用 java.net.URLEncoder.encode(String, Charset) 对参数进行编码:

  UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseURL);
    if (params != null) {
      for (final Entry<String, String> entry : params.entrySet()) {
        var encoded=URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8);
        builder.queryParam(entry.getKey(), encoded);
      }
    }

然而,这引入了“%”作为一个特殊字符,它实际上触发了构建器中的编码,因此日期参数被编码了 2 次。

input string: 2020-07-09T00:14:15.230699+03:00
result after first encoding: 2020-07-09T00%3A14%3A15.230699%2B03%3A00
final result: http://localhost:8090/remainingAddress?fromDate=2020-07-09T00%253A14%253A15.230699%252B03%253A00&toDate=2020-07-09T00%253A14%253A15.31158%252B03%253A00

执行请求后,我在尝试解析日期时收到以下输入:2020-07-09T00%253A14%253A15.230699%252B03%253A00(相当混乱)。

注意本项目使用 Spring Boot V2.5.5。

我的问题是我应该如何提供查询参数以便正确编码?或者也许这个构建器不适合与特殊字符一起使用?

【问题讨论】:

  • 嗨,我也遇到了同样的问题。你有没有找到解决办法?
  • 是的,阅读后我发现我必须从使用 URL 字符串切换到 URI 对象。 URI uri = UriComponentsBuilder.fromHttpUrl(baseUrl).queryParam("paramName", value).build().encode().toUri(); 如果我们将此对象传递给其余模板,则编码将按预期进行。

标签: java spring-boot urlencode


【解决方案1】:

注意:这是 Kotlin 实现

我最近遇到了这个问题,

我的一个端点的范围限制为查询参数,类型为 OffsetDateTime。

这有时类似于 UTC 时间戳,例如 2021-01-13T02:00Z 或具有类似 2021-01-13T13:00+11:00 的区域偏移量,其中两者都等于 2021-01-13T13:00 ZoneId 的 LocalDateTime Australia/Melbourne

最初,我尝试像这样构建 uri:

val uri = UriComponentsBuilder.fromUriString(baseApi.url)
        .path("/v1/products/${productId}/orders")
        .queryParam("from", from)
        .queryParam("to", to)
        .queryParam("type", type)
        .build().encode().toUri()

这适用于 UTC 时间戳,但不能使用偏移量编码时间戳。就像你的情况一样。

那么这对我来说是固定的:

val uri = UriComponentsBuilder.fromUriString(baseApi.url)
        .path("/v1/products/${productId}/orders")
        .queryParam("from", "{from}")
        .queryParam("to", "{to}")
        .queryParam("type", type)
        .encode().buildAndExpand(from, to).toUri()

这有助于在 buildAndExpand 时将 OffsetDateTime 作为变量注入字符串。此处的字符串插值通过添加那些特殊的转义字符来修复任何 uriString 问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-14
    • 2013-02-03
    • 1970-01-01
    • 2018-06-26
    • 2010-10-23
    • 2016-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多