Java 11中java.net.URI为何不编码所有保留字符?
Java.net.URI构造函数的编码逻辑疑问及自定义编码实现困惑
我想用scheme、userInfo、host、port、path、query、fragment这些独立URI组件创建java.net.URI实例,该类提供了对应的构造函数,源码如下:
public URI(String scheme, String authority, String path, String query, String fragment) throws URISyntaxException { String s = toString(scheme, null, authority, null, null, -1, path, query, fragment); checkPath(s, scheme, path); new Parser(s).parse(false); }
该构造函数会对path、query和fragment部分进行编码,若传入已编码字符串会导致双重编码。
根据该构造函数的JavaDoc描述:
- 若传入path,则追加该路径。仅对非未保留字符、非标点字符、非转义字符,且不是斜杠(
/)或@字符的内容进行编码。 - 若传入query,则追加问号(
?)和query内容。仅对非法URI字符进行编码。 - 若传入fragment,则追加哈希(
#)和fragment内容。仅对非法URI字符进行编码。
其中明确,未保留字符、标点字符(包含!、#、$、&、'、(、)、*、+、,、;、=、:)以及转义字符不会被编码。
根据RFC 3986的定义,保留字符分为以下两类:
reserved = gen-delims / sub-delims gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
我的疑问是,@、/、+明明属于保留字符,为什么java.net.URI的构造函数不对它们进行编码?
比如下面的测试代码:
String scheme = "http"; String userInfo = "username:password"; String host = "example.com"; int port = 80; String path = "/path/t+/resource"; String query = "q=search+term"; String fragment = "section1"; URI uri = new URI(scheme, userInfo, host, port, path, query, fragment); uri.toString(); // 结果中path里的`+`不会被编码
我还困惑,如果这种行为是正确的,那RFC为什么要把这些字符定义为保留字符?另外我正尝试实现一个完整URI字符串的编码函数,需要提取各组件分别编码后再重组,现在不知道该遵循哪种规则。
内容的提问来源于stack exchange,提问作者shotex
相关产品推荐
相关产品推荐

