我有一个奇怪的问题,即将一个加号+
的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();
未编码的查询如下所示:
https://example.com?update=2017-01-05T12:40:44+01
编码后的字符串会产生:
https://example.com?update=2017-01-05T12:40:44%2B01
这是(恕我直言)一个正确编码的查询字符串。请参阅%2B
替换查询字符串末尾的+
中的+01
。
但是,现在,当我使用编码的url针对API发送请求时,我收到一条错误消息,指出无法处理请求。
但是,如果我在发送请求之前将%2B
替换为+
,则可行:
url.replaceAll("%2B", "+");
据我了解,+
符号代替whitespace
。因此,解码后服务器真正看到的URL必须是
https://example.com?update=2017-01-05T12:40:44 01
我对这个假设是对的吗?
除了奇怪的非标准字符串替换之外,除了联系API的所有者以使其使用正确编码的查询之外,我能做些什么吗?
更新:
根据规范RFC 3986(第3.4节),查询参数中的+
符号不需要编码。
3.4。查询
查询组件包含非分层数据 路径组件(第3.3节)中的数据用于识别
URI的方案和命名权限范围内的资源 (如果有的话)。查询组件由第一个问题
指示 标记(“?”)字符并以数字符号(“#”)字符终止 或者在URI的末尾。Berners-Lee,et al。标准跟踪[页面 23] RFC 3986 URI通用语法
2005年1月query = *( pchar / "/" / "?" )
字符斜杠(“/”)和问号(“?”)可以表示 查询组件中的数据。要小心一些年纪大了,错了 当实现它时,实现可能无法正确处理这些数据 相对引用的基URI(第5.1节),显然是
因为他们无法区分查询数据和路径数据 寻找分层分隔符。但是,作为查询组件
通常用于以形式承载识别信息 “key = value”对和一个常用值是对
的引用 另一个URI,有时候可用性更好,以避免百分比 编码那些字符。
根据this answer on stackoverflow,spring的UriComponentBuilder使用了这个规范,但显然它并不是真的。那么一个新的问题是,如何使UriComponentBuilder遵循规范?
答案 0 :(得分:0)
编码2017-01-05T12:40:44+01
为您提供2017-01-05T12%3A40%3A44%2B01
而不是您建议的2017-01-05T12:40:44%2B01
。
也许这就是为什么服务器无法处理您的请求,它是半个编码日期。
答案 1 :(得分:0)
所以看起来Spring的UriComponentBuilder对整个网址进行编码,在false
方法中将编码标记设置为build()
无效,因为toUriString()
方法总是编码该网址在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();
}
我(现在)的解决方案是编码真正需要手动编码的内容。另一个解决方案可能是(可能需要编码)获取URI并在
上进一步使用String url = uriComponentsBuilder.build().toUri().toString(); // returns the unencoded url as a string
答案 2 :(得分:0)
在org / springframework / web / util / HierarchicalUriComponents.java中
QUERY_PARAM {
@Override
public boolean isAllowed(int c) {
if ('=' == c || '+' == c || '&' == c) {
return false;
}
else {
return isPchar(c) || '/' == c || '?' == c;
}
}
}
不允许使用字符'+',因此会对其进行编码
答案 3 :(得分:0)
您可以使用 builder.build().toUriString()
这对我有用
谢谢