【发布时间】: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