如文档中所述,Uri
构建和解析符合RFC 2396的 URI 引用。
如果您向下滚动到规范中的第 2.4.3 节,您会发现以下内容:
其他字符被排除在外,因为已知网关和其他传输
代理有时会修改这些字符,或者它们被
用作分隔符。
unwise = "{" | "}" | "|" | "\" | "^" | "[" | "]" | "
"`
对应于排除字符的数据必须转义才能在 URI 中正确表示。
从代码的角度来看,Uri
有一个私有方法来确定一个字符是否被允许——如果不允许,它将被编码。理论上,这应该返回false
括号和其他特殊字符。
/**
* Returns true if the given character is allowed.
*
* @param c character to check
* @param allow characters to allow
* @return true if the character is allowed or false if it should be
* encoded
*/
private static boolean isAllowed(char c, String allow) {
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9')
|| "_-!.~'()*".indexOf(c) != NOT_FOUND
|| (allow != null && allow.indexOf(c) != NOT_FOUND);
}
话虽如此,现在我们进入了有趣的部分。它看起来Uri.parse()
相当“懒惰”,因为它实际上并没有对你给它的 uri 进行编码。在您的场景中,您可能正在Uri
通过调用构建:
Uri uri = Uri.parse("http://host/path?param1=1¶m2[]=2¶m3[1]=3");
然后,当您开始调用getQueryParameter()
结果Uri
时,会发生支持数据 (a String
) 是“未编码”的情况,但您提供给这些方法的参数名称确实会被编码。例如:
uri.getQueryParameter("param2[]")
事实上是:
uri.getQueryParameter("param2%5B%5D")
带键的查询参数param2%5B%5D
显然不存在于Uri
.
解决方案是首先确保括号被转义,或者使用Uri.Builder
. 例如:
Uri uri = Uri.parse("http://host/path").buildUpon()
.appendQueryParameter("param1", "1")
.appendQueryParameter("param2[]", "2")
.appendQueryParameter("param3[1]", "3")
.build();
这将导致以下底层 uri:
http://host/path?param1=1¶m2%5B%5D=2¶m3%5B1%5D=3
然后您可以uri.getQueryParameter("param3[1]")
毫无问题地调用:它会返回3
.
编辑:我收回我所说Uri.parse()
的懒惰。本来就是这样的。正如Javadoc中明确提到的:
创建一个解析给定编码URI 字符串的 Uri。
换句话说:您为解析提供的字符串应该已经正确编码。