奇怪的网址编码问题

Mic*_*el 7 java urlencode

我有一个奇怪的问题,urlencoding加号+作为针对API的请求的查询参数.API的文档说明:

日期必须采用W3C格式,例如'2016-10-24T13:33:23 + 02:00'.

到目前为止一直很好,所以我使用这个代码(minimalized)生成url,使用Spring的UriComponentBuilder:

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssX");
ZonedDateTime dateTime = ZonedDateTime.now().minusDays(1);
String formated = dateTime.format(formatter);

UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUriString(baseUrl);
uriComponentsBuilder.queryParam("update", formated);
uriComponentsBuilder.build();
String url = uriComponentsBuilder.toUriString();
Run Code Online (Sandbox Code Playgroud)

未编码的查询将如下所示:

https://example.com?update=2017-01-05T12:40:44+01
Run Code Online (Sandbox Code Playgroud)

编码的字符串导致:

https://example.com?update=2017-01-05T12:40:44%2B01
Run Code Online (Sandbox Code Playgroud)

这是(恕我直言)一个正确编码的查询字符串.请参阅%2B替换查询字符串末尾的+in +01.

但是,现在,当我使用编码的url针对API发送请求时,我收到一条错误消息,指出无法处理请求.

但是,如果我在发送请求之前将其替换为%2Ba +,则可以:

url.replaceAll("%2B", "+");
Run Code Online (Sandbox Code Playgroud)

从我的理解,+标志是一个替代whitespace.因此,解码后服务器真正看到的URL必须是

https://example.com?update=2017-01-05T12:40:44 01
Run Code Online (Sandbox Code Playgroud)
  • 我对这个假设是对的吗?

  • 有什么我可以做的,除了联系API的所有者使其使用正确编码的查询,除了奇怪的非标准字符串替换?

更新:

根据规范RFC 3986(第3.4节),+查询参数中的符号不需要编码.

3.4.询问

查询组件包含非分层数据,与路径组件(第3.3节)中的数据一起用于标识
URI方案和命名权限
(如果有)范围内的资源.查询组件由第一个
问号("?")字符表示,并以数字符号("#")字符
或URI的末尾结束.

伯纳斯 - 李等人.标准跟踪[第23页] RFC 3986 URI通用语法
2005年1月

  query       = *( pchar / "/" / "?" )
Run Code Online (Sandbox Code Playgroud)

字符斜杠("/")和问号("?")可以表示查询组件中的数据.请注意,当某些较旧的错误实现用作相对引用的基本URI时(第5.1节),可能无法正确处理此类数据,这显然是
因为它们在
查找分层分隔符时无法区分查询数据和路径数据.但是,由于查询组件
通常用于携带
"key = value"对形式的标识信息,而一个常用值是对
另一个URI 的引用,因此有时可以更好地避免
对这些字符进行百分比编码.

根据stackoverflow上的这个答案,spring的UriComponentBuilder使用了这个规范,但显然它并不是真的.那么一个新的问题是,如何使UriComponentBuilder遵循规范?

chr*_*con 1

所以看起来spring的UriComponentBuilder对整个url进行编码,falsebuild()方法中将编码标志设置为没有效果,因为该toUriString()方法总是对url进行编码,因为它encode()在之后显式调用build()

/**
 * Build a URI String. This is a shortcut method which combines calls
 * to {@link #build()}, then {@link UriComponents#encode()} and finally
 * {@link UriComponents#toUriString()}.
 * @since 4.1
 * @see UriComponents#toUriString()
 */
public String toUriString() {
    return build(false).encode().toUriString();
}
Run Code Online (Sandbox Code Playgroud)

对我来说(目前)的解决方案是对真正需要手动编码的内容进行编码。另一个解决方案可能是(可能也需要编码)获取 URI 并进一步使用它

String url = uriComponentsBuilder.build().toUri().toString(); // returns the unencoded url as a string
Run Code Online (Sandbox Code Playgroud)