奇怪的网址编码问题

时间:2017-01-06 12:00:09

标签: 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();

未编码的查询如下所示:

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遵循规范?

4 个答案:

答案 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()

这对我有用

谢谢