文章目录
- 1. 简介
- 2. 构造一个URI
- 3. URI的各个部分
- 4. 解析相对URI
- 5. 相等性和比较
- 6. 字符串表示
1. 简介
URI是对URL的抽象,不仅包含统一资源定位符,还包括统一资源名(URN)。实际使用的URI大多是URL,但大多数规范和标准都是用URI定义的,在Java中用java.net.URI类表示,这个类与java.net.URL类的区别表现在3个重要的方面:
- URI类完全有关于资源的标识和URI的解析。它没有提供方法来获取URI所标识资源的表示
- 相比于URL,URI类与相关的规范更一致
- URI对象可以表示相对URI,URL类在存储URI时会将其绝对化。
简而言之,URL对象是对应网络获取的应用层协议的一个表示,而URI对象纯粹用来解析和处理字符串。URI类没有网络获取功能,尽管URL类有一些字符串解析方法,如getFIle等,但其中很多方法都有问题,与相关的规范要求的行为不完全一样。正常情况下,假如你想下载一个URL的内容,应该使用URI类,如果想使用URL来完成表示而不是获取(例如表示一个XML的命名空间),就应该使用URI类,二者都需要时使用toURI将URL对象转换为URI对象,或使用toURL将URL对象转换为URI对象。(见我这篇博客)
2. 构造一个URI
URI从字符串构造,可以把整个URI通过一个字符串传入构造函数,也可以部分传入
//根据任何满足条件的字符串创建一个新的URI对象
public URI(String uri)throws URISyntaxException
//需要一个模式的特定部分,主要用于非URI。模式是URI的协议,
public URI(String scheme,String schemeSpecificPart, String fragment)throws URISyntaxException
public URI(String scheme,String host ,String path, String fragment)throws URISyntaxException
public URI(String scheme,String authority, String path,String Query,String fragment)throws URISyntaxException
public URI(String scheme,String userInfo,String host,String query,int port ,String path, String query,String fragment)throws URISyntaxException
与URL类不同,URI类不依赖底层任何协议处理器,只要语法正确,java就不需要为了创建URI对象而理解协议,因此,不同于URL类,URI类可以用于新的实验性的URI模式。如果你确信你的URI是有效的,不违反任何规则,那么可以使用静态工厂方法URI.create(),与构造函数不同,它不会抛出URISyntaxException。
3. URI的各个部分
URI引用包括最多的三个部分:模式、模式特定部分和片段标识符,一般格式为:模式:模式特定部分:片段
。URI提供了一些获取方法,可以返回各个URI对象的这三个部分。getRawFoo()方法返回URI各个部分的编码形式,相应的getFoo()方法首先对所有百分号转义的字符进行编码,然后返回编码的各个部分。
public String getScheme()
public String getSchemeSpecificPart()
public String getRawSchemeSpecificPart()
public String getRawFragment()
isAbsolute()
方法会检查一个URI是绝对URI还是相对URI,如果没有模式则为绝对URI,否则为相对URI。模式特定部分的细节根据模式类型不同会有差别,例如tel URI中,模式特定语法类似于电话号码,模式特定部分都有一个特定的分层格式,划分为授权机构、路径和查询字符串。授权机构进一步分为用户信息、主机和端口。如果URI是一个层次URI时,isOpaque()会返回false,否则就会返回true。 如果URI不透明,只能得到模式、模式特定部分和片段标识符。不过,如果URI是层次URI,那么URI所有不同部分都会有相应的获取方式。
在计算机网络中,URI(Uniform Resource Identifier,统一资源标识符)是用于标识和定位资源的字符串。URI可以分为透明(transparent)和不透明(opaque)两种类型。
- 透明URI:透明URI包含可以直接解读和理解的信息。例如,一个透明URI可以包含网络协议(如http://或https://)、域名(如www.example.com)和路径(如/resource)等信息。这些信息可以被计算机和网络设备直接解析和使用,以定位和访问资源。透明URI通常用于Web浏览器和其他网络应用程序中。
示例透明URI:https://www.example.com/resource- 不透明URI:不透明URI是指包含一些不可直接解析或理解的信息的标识符。这种类型的URI可能包含加密数据、特定的内部标识符或其他对外部用户来说是不可见或不可理解的信息。不透明URI一般不会被直接使用于网络浏览器或应用程序,而是在应用程序内部使用,用于内部逻辑或身份验证等目的。
示例不透明URI:example://internal/resource/1234需要注意的是,透明URI和不透明URI的定义并非严格规定,而是根据上下文和使用环境而定。有时,不同的应用程序或系统可能会使用相同的URI格式,但其解释和处理方式可能不同。因此,在具体的应用或协议中,需要查阅相关文档以了解URI的使用方式和解析规则。
public String getAuthority()
public String getFragment()
public String getHost()
public String getPath()
public String getPort()
public String getQuery()
public String getUserInfo()
上面这些方法都会返回解码后的部分。(加密的部分会进行还原)如果希望得到URI原始的编码部分,见下面方法:
public String getRawAuthority()
public String getRawFragment()
public String getRawPath()
public String getRawQuery()
public String getRawUserInfo()
出于各种技术的原因Java并不会总是在开始就检测授权机构部分中的语法错误,但这个没有多少实际影响。不做这个检测的直接后果是,一般无法返回授权机构的各个部分:端口、主机和用户信息。在这种情况下,可以调用parseServerAuthirity(),强制重新解析授权机构。
4. 解析相对URI
URI类提供了3个方法可以在绝对和相对URI之间来回的切换
public URI resolve(URI uri)
public URI resolve(String uri)
public URI relativize(URI uri)
resolve()方法将uri参数与这个URI进行比较,并用它构造一个URI对象,这个对象包装了一个绝对的URI
public class QuizCardBuilder {
public static void main(String[] args) throws URISyntaxException {
URI absoulte=new URI("http://www.example.com/");
URI relatice=new URI("images/logo.png");
System.out.println(absoulte.resolve(relatice));
}
}
如果调用本身不包含绝对URI,那么resolve方法将尽可能地解析URI,并返回一个新的相对URI对象作为结果。
public class QuizCardBuilder {
public static void main(String[] args) throws URISyntaxException {
URI absoulte=new URI("javafaq/books/");
URI relatice=new URI("images/logo.png");
System.out.println(absoulte.resolve(relatice));
}
}
还可以反向完成以上过程,即从绝对URI变为相对URI。relativeize()方法根据相对于调用URI的uri参数创建一个新的URI对象。
public class QuizCardBuilder {
public static void main(String[] args) throws URISyntaxException {
URI absoulte=new URI("http://www.example.com/iamges/log.png");
URI relatice=new URI("http://www.example.com/");
System.out.println(relatice.relativize(absoulte));
}
}
5. 相等性和比较
URI的比较和URL一样不是单纯的字符串比较,相等的URI必须都是层次的或不透明的。比较模式和授权机构是不考虑大小写。也就是说,http和HTTP是相同的模式,www.example.com与www.EXAMPLE.com是相同的授权机构。URI的其余部分要区分大小写。转义字符在比较之前不会解码。
- hashcode()方法与相等性是一致的,相等的URI具有相等的散列值。
- URI不同与URL它实现了Comparable接口,因此URI可以排序,基于各个部分的字符串比较,按一下顺序进行排序:
- 如果模式不同就比较模式,不考虑大小
- 否则,如果模式相同,一般认为有层次的URI小于有相同模式的不透明URI
- 如果两个URI都是不透明的URI,则根据模式的特定部分对它们排序
- 如果模式和不透明的模式特有部分都相同,就根据片段比较URI
- 如果两个URI都是层次URI,则根据它们的授权机构部分排序,授权机构本身依次,根据用户信息、主机和端口排序。主机比较不区分大小
- 如果模式和授权机构都相等,就使用路径来区分
- 如果路径也相等,就比较查询字符串
- 如果查询字符串也相等,就比较片段
6. 字符串表示
有两个方法可以将URI对象转换为字符串:
public String toString()
public Stirng toASCIIString()
前者返回URI的未编码的字符串,因此这个方法的结果不能保证是一个语法正确的URI,尽管实际上它是正确的。后者返回URI编码的字符串形式,会进行解码。