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 之类的编码有同样的问题。