当前位置: 首页 > news >正文

[转载]URI 源码分析

需要提前了解下什么是URI,及URI和URL的区别:
URI、 URL 和 URN 的区别

URI 引用包括最多三个部分:模式、模式特定部分和片段标识符。一般为:
模式:模式特定部分:片段
如果省略模式,这个URI引用则是相对的。如果省略片段标识符,这个URI引用就是一个纯URI。

URI是对URL的抽象,不仅包括统一资源定位符URL,还包括统一资源名URN。实际上使用的URI大多都是URL。在java中,URI使用java.net.URI类表示,URI类只能标识资源,和解析URI,而不能获取URI所标识的资源(URN是无法定位到资源的)。

构造

public URI(String str) throws URISyntaxException { new Parser(str).parse(false); } public URI(String scheme, String host, String path, String fragment) throws URISyntaxException{ this(scheme, null, host, -1, path, null, fragment); } public URI(String scheme, String authority, String path, String query, String fragment) throws URISyntaxException{ .... } public URI(String scheme, String userInfo, String host, int port, String path, String query, String fragment) throws URISyntaxException{ ... } public URI(String scheme, String ssp, String fragment) throws URISyntaxException { new Parser(toString(scheme, ssp, null, null, null, -1, null, null, fragment)).parse(false); } 

URI类提供了5中构造方法

  1. 根据提供的一个uri字符串构造一个URI对象。
  2. 主要针对层次的URI。通过 模式、服务器地址、文件路径、片段标识构造URI。
  3. 主要针对层次的URI。通过 模式、授权机构、文件路径、查询条件、片段标识构造URI。
  4. 主要针对层次的URI。通过 模式、用户信息、服务器地址、端口、文件路径、查询条件、片段标识构造URI。
  5. 主要针对非层次URI。通过 模式、模式特定部分和片段标识创建URI。

create方法

public static URI create(String str) { try { return new URI(str); } catch (URISyntaxException x) { throw new IllegalArgumentException(x.getMessage(), x); } } 

如果可以确认URI的格式正确,可使用create的工厂方法创建URI。因为该方法不会抛出URISyntaxException异常。

是否透明URL

URI通常情况下都是层次(带“/”)的,但是也有不透明(没有“/”)的,层次的URI包含模式,主机,站点等各个部分,当然可能某些部分不包含,但是不透明的URI只包含三个部分,Scheme,Scheme-specific-part,Fragment.
如:mailto:jijianshuai@infcn.com.cn

public boolean isOpaque() { return path == null; } 

判断path是否为空,如果为空则是不透明的,说明URI中没有“/”。

 
Paste_Image.png

在URI构造器中解析URI,代码:new Parser(str).parse(false);

判断URI中是否存在“/”符号,如果存在就是有层次结构的URI。
如果存在“/”,则调用parseAuthority方法进行解析path。

URI获取各部分信息

  1. 获得模式
    public String getScheme();
  2. 获得模式特定部分
    public String getSchemeSpecificPart();
    public String getRawSchemeSpecificPart();
  3. 获得片段
    public String getFragment();
    public String getRawFragment();
  4. 获得授权机构
    public String getAuthority();
    public String getRawAuthority()
    授权机构包括:用户信息、服务器地址(域名或ip)、端口
    user:password@localhost:80
  5. 获取片段标识
    public String getFragment()
    public String getRawFragment()
  6. 获取服务器地址(域名或ip)
    public String getHost()
  7. 获取路径
    public String getPath()
    public String getRawPath()
    路径包括(目录结构和文件部分)。如:/dir/index.html
  8. 获取端口
    public int getPort()
    如果没有端口则返回-1;
  9. 获取URI的查询字符串
    public String getQuery()
    public String getRawQuery()
  10. 获取用户信息
    public String getUserInfo()
    public String getRawUserInfo()

如果URI是非透明只能获取到1~3个信息。
如果URI是层次结构则能获取所有信息。

方法中带Raw的,是获取编码后的URI部分信息。非ascii的字符需要进行编码,不带Raw的方法是解码后的信息。

getScheme、getHost、getPort这三个方法没有Raw方法,是因为这三部分不会出现非ascii的字符。

resolve 方法

resolve方法可以将相对URI转换成绝对URI。示例如下:

URI a = URI.create("http://localhost:8080/index.html");
URI b = URI.create("user/userInfo.html");
URI c = a.resolve(b);
System.out.println(c);

根据a获取b的绝对路径

打印结果为:http://localhost:8080/user/userInfo.html

源码如下
public URI resolve(URI uri) { return resolve(this, uri); } private static URI resolve(URI base, URI child) { // check if child if opaque first so that NPE is thrown // if child is null. if (child.isOpaque() || base.isOpaque()) return child; // 5.2 (2): Reference to current document (lone fragment) if ((child.scheme == null) && (child.authority == null) && child.path.equals("") && (child.fragment != null) && (child.query == null)) { if ((base.fragment != null) && child.fragment.equals(base.fragment)) { return base; } URI ru = new URI(); ru.scheme = base.scheme; ru.authority = base.authority; ru.userInfo = base.userInfo; ru.host = base.host; ru.port = base.port; ru.path = base.path; ru.fragment = child.fragment; ru.query = base.query; return ru; } // 5.2 (3): Child is absolute if (child.scheme != null) return child; URI ru = new URI(); // Resolved URI ru.scheme = base.scheme; ru.query = child.query; ru.fragment = child.fragment; // 5.2 (4): Authority if (child.authority == null) { ru.authority = base.authority; ru.host = base.host; ru.userInfo = base.userInfo; ru.port = base.port; String cp = (child.path == null) ? "" : child.path; if ((cp.length() > 0) && (cp.charAt(0) == '/')) { // 5.2 (5): Child path is absolute ru.path = child.path; } else { // 5.2 (6): Resolve relative path ru.path = resolvePath(base.path, cp, base.isAbsolute()); } } else { ru.authority = child.authority; ru.host = child.host; ru.userInfo = child.userInfo; ru.host = child.host; ru.port = child.port; ru.path = child.path; } // 5.2 (7): Recombine (nothing to do here) return ru; } 
  1. 是否是非透明URI,如果是,则直接返回child。
  2. 判断child是否只有fragment(片段标识)。如果child只有片段标识则执行2.1。否则执行3。
    2.1 如果child的fragment和base的片段标识一样,就直接返回base的url
    2.2 把base不包含fragment的部分和child的fragment构造一个新的URI返回。
  3. 判断child的scheme不为空则直接返回child。不为空说明他是绝对路径。
  4. 根据base的URI各部分构造child的绝对路径URI并返回。

relativize 方法

relativize 方法可以将绝对路径的URI转换成相对路径的URI。

URI a = URI.create("http://localhost:8080/");
URI b = URI.create("http://localhost:8080/index.html");
URI c = a.relativize(b);
System.out.println(c);

获取b相对a的相对路径。

打印的结果为:index.html

private static URI relativize(URI base, URI child) { // check if child if opaque first so that NPE is thrown // if child is null. if (child.isOpaque() || base.isOpaque()) return child; if (!equalIgnoringCase(base.scheme, child.scheme) || !equal(base.authority, child.authority)) return child; String bp = normalize(base.path); String cp = normalize(child.path); if (!bp.equals(cp)) { if (!bp.endsWith("/")) bp = bp + "/"; if (!cp.startsWith(bp)) return child; } URI v = new URI(); v.path = cp.substring(bp.length()); v.query = child.query; v.fragment = child.fragment; return v; } 
  1. 判断child是否不是透明URI,如果不是则直接返回child。不是层次结构的uri是没有相对路径的。
  2. 判断两个URI的scheme和授权机构是否不同,如果不同则直接返回child。
  3. 判断base是否“/”结尾,如果不是则加上“/”
  4. 判断child是否以base开头,如果不是则直接返回child。
  5. 返回child中,不包含base的部分,构造一个新URI返回。


作者:jijs
链接:https://www.jianshu.com/p/24a2da876372
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转载于:https://www.cnblogs.com/AaronBear/p/10552932.html

相关文章:

  • HTML之常用标签及属性
  • jmeter 常见问题汇总
  • SPOJ COT3.Combat on a tree(博弈论 Trie合并)
  • HDU 2883 kebab
  • C++学习笔记30,指针的引用(2)
  • fatal error C1010: 在查找预编译头时遇到意外的文件结尾
  • c# Winform dev控件之ChartControl
  • Spring框架学习07——基于传统代理类的AOP实现
  • html迪士尼网页实现代码
  • HDU 2159 FATE
  • es 基于match_phrase/fuzzy的模糊匹配原理及使用
  • spring_事務
  • ASP.NET Core OData now Available
  • 01背包 完全背包 算法解析
  • 解决任务计划程序未启动任务,因为相同任务的实例正在运行的问题
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • android图片蒙层
  • css布局,左右固定中间自适应实现
  • css选择器
  • orm2 中文文档 3.1 模型属性
  • SQLServer之索引简介
  • 阿里云Kubernetes容器服务上体验Knative
  • 聊聊redis的数据结构的应用
  • 面试总结JavaScript篇
  • 浅析微信支付:申请退款、退款回调接口、查询退款
  • 我的业余项目总结
  • 我感觉这是史上最牛的防sql注入方法类
  • 学习HTTP相关知识笔记
  • ​比特币大跌的 2 个原因
  • # 日期待t_最值得等的SUV奥迪Q9:空间比MPV还大,或搭4.0T,香
  • #git 撤消对文件的更改
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (1/2)敏捷实践指南 Agile Practice Guide ([美] Project Management institute 著)
  • (C)一些题4
  • (c语言版)滑动窗口 给定一个字符串,只包含字母和数字,按要求找出字符串中的最长(连续)子串的长度
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (超简单)构建高可用网络应用:使用Nginx进行负载均衡与健康检查
  • (附源码)springboot建达集团公司平台 毕业设计 141538
  • (四)图像的%2线性拉伸
  • (五)MySQL的备份及恢复
  • *_zh_CN.properties 国际化资源文件 struts 防乱码等
  • *Django中的Ajax 纯js的书写样式1
  • .gitignore文件---让git自动忽略指定文件
  • .net core 6 使用注解自动注入实例,无需构造注入 autowrite4net
  • .NET Core WebAPI中封装Swagger配置
  • .NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions
  • .NET Framework与.NET Framework SDK有什么不同?
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 中 GetProcess 相关方法的性能
  • .Net接口调试与案例
  • [20161101]rman备份与数据文件变化7.txt
  • [Angular] 笔记 8:list/detail 页面以及@Input
  • [C++] sqlite3_get_table 的使用
  • [emacs] CUA的矩形块操作很给力啊