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这样的编码问题。
答案 0 :(得分:1)
查询字符串
a=b&c
在URI中没有错。 RFC on URI Generic Syntax states
查询组件是一串要解释的信息 资源。
query = *uric
在查询组件中,字符“;”,“/”,“?”,“:”,“@”,
“&”,“=”,“+”,“,”和“$”是保留的。
查询字符串中的字符&
非常有效(uric
表示保留字符,标记字符和字母数字字符)。 RFC还声明
许多URI包括由某些组成或由其分隔的组件 特殊字符。这些字符称为“保留”,因为
它们在URI组件中的使用仅限于它们的保留
目的。 如果URI组件的数据与中和 保留目的,然后必须在之前转义冲突的数据 形成URI。
由于&
有效但保留,因此用户需要确定是否要进行编码。
您所谓的查询参数不是URI的一项功能,因此URI
类没有理由(也不应该)支持它。
相关:
答案 1 :(得分:1)
我发现的唯一解决方法是使用单参数构造函数和方法。请注意,您必须使用URI#getRawQuery()
来避免解码%26
。例如:
URI uri = new URI("http://a/?b=c%26d&e");
// uri.getRawQuery() equals "b=c%26d&e"
uri = new URI(new URI(uri.getScheme(), uri.getAuthority(),
uri.getPath(), null, null) + "?f=g%26h&i");
// uri.getRawQuery() equals "f=g%26h&i"
uri = uri.resolve("?j=k%26l&m");
// uri.getRawQuery() equals "j=k%26l&m"
// uri.toString() equals "http://a/?j=k%26l&m"
答案 2 :(得分:0)
我所熟知的单一工作解决方案是反思(见https://blog.stackhunter.com/2014/03/31/encode-special-characters-java-net-uri/)
URI uri = new URI("http", null, "example.com", -1, "/accounts", null, null);
Field field = URI.class.getDeclaredField("query");
field.setAccessible(true);
field.set(uri, encodedQueryString);
//clear cached string representation
field = URI.class.getDeclaredField("string");
field.setAccessible(true);
field.set(uri, null);
答案 3 :(得分:-1)
使用URLEncoder.encode()
方法,例如:
URLEncoder.encode("a=x%20y", "ISO-8859-1");