java.net.URI 和查询参数值中的百分比

标签 java encoding uri percent-encoding

System.out.println(
    new URI("http", "example.com", "/servlet", "a=x%20y", null));

结果是http://example.com/servlet?a=x%2520y ,其中查询参数值与提供的参数值不同。奇怪,但这确实遵循 Javadoc:

“百分比字符 ('%') 总是被这些构造函数引用。”

我们可以传递解码后的字符串,a=x y然后我们得到一个合理的(?)结果a=x%20y .

但是如果查询参数值中包含“&”字符呢?例如,如果该值是带有查询参数的 URL 本身,就会发生这种情况。看看这个(错误的)查询字符串: a=b&c .必须在此处转义符号 ( a=b%26c ),否则这可以被视为查询参数 a=b和一些垃圾(c)。如果我将其传递给 URI 构造函数,它会对其进行编码,并返回错误的 URL:...?a=b%2526c

这个问题似乎使 java.util.URI 变得无用。我在这里遗漏了什么吗?

答案总结

java.net.URI 确实知道 URI 的查询部分的存在,但它不了解查询部分的内部结构,这可能因方案而异。例如 java.net.URI 不了解 HTTP 查询部分的内部结构。如果 java.net.URI 将查询视为不透明字符串并且不更改它,这将不是问题。但它试图应用一些通用的百分比编码算法,这会破坏 HTTP URL。

因此,我无法使用 URI 类从其各个部分可靠地组装 URL,尽管它有构造函数。我还要提到的是,从 Java 7 开始,相对化操作的实现非常有限,只有当一个 URL 是另一个 URL 的前缀时才有效。这两个功能(以及用于这些目的的更精简的界面)是我对 java.net.URI 感兴趣的原因,但它们都不适合我。

最后我使用java.net.URL 进行解析,并编写代码将部分组合成一个URL 并将两个URL 相对化。我还检查了 Apache HttpClient URIBuilder 类,虽然它确实了解 HTTP 查询字符串的内部结构,但从 4.3 开始,在处理整个查询部分时,它与 java.net.URI 等编码有同样的问题。

最佳答案

查询字符串

a=b&c

在 URI 中没有错误。 RFC on URI Generic Syntax states

The query component is a string of information to be interpreted by the resource.

  query         = *uric

Within a query component, the characters ";", "/", "?", ":", "@",
"&", "=", "+", ",", and "$" are reserved.

查询字符串中的字符 & 非常有效(uric 代表保留字符、标记字符和字母数字字符)。 RFC 还指出

Many URI include components consisting of or delimited by, certain
special characters. These characters are called "reserved", since
their usage within the URI component is limited to their reserved
purpose. If the data for a URI component would conflict with the
reserved purpose, then the conflicting data must be escaped before
forming the URI.

因为 & 有效但被保留,由用户决定是否要编码。

您所说的查询参数 不是 URI 的功能,因此 URI 类没有理由(也不应该)支持它。

相关:

关于java.net.URI 和查询参数值中的百分比,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19917079/

相关文章:

javascript - 为什么 javascript 中的 `btoa` 编码适用于 20 位字符串而不是 20 位 int?

java - 事务提交后更新查询未刷新

java - 当我运行应用程序时,已排序的 ArrayList 未显示为已排序

java - 在存储之前和从 KeyStore 检索之后,SecretKey 的 Base64 编码值不同

windows - Perl:在 Windows 上管理路径编码

带有 URL 列表的 MySQL 数据库 - 如何检查损坏的链接?

postgresql - 如何使用带有 createdb 和 URI 的终端?

java - 在 Android 中将字符串转换为 Uri

java - Hibernate 返回不匹配的行

java - Junit of equals 方法