Java魔法堂:URI、URL(含URL Protocol Handler)和URN

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介:

一、前言                              

  过去一直搞不清什么是URI什么是URL,现在是时候好好弄清楚它们了!本文作为学习笔记,以便日后查询,若有纰漏请大家指正!

 

二、从URI说起                            

 1. 概念

  URI(Uniform Resource Identifier,统一资源标识符)以字符串来表示某种资源的统一资源标识。

  格式为: [scheme:]scheme-specific-part[#fragment] 

  [scheme:]组件 ,URI的名称空间标识。

  scheme-specific-part组件 ,用于标识资源,内部格式由具体的 scheme 来决定。

  [#fragment]组件 ,井号(#)作为fragment组件的起始字符,而fragment组件则用于聚焦到资源的某个部分。

 2. 绝对URI和相对URI

  绝对URI:以scheme组件起始的完整格式,如http://fsjohnhuang.cnblogs.com。表示以对标识出现的环境无依赖的方式引用资源。

  相对URI:不以scheme组件起始的非完整格式,如fsjohnhuang.cnblogs.com。表示以对依赖标识出现的环境有依赖的方式引用资源。

  实例:当前页面地址为http://fsjohnuang.cnblogs.com

复制代码
// html snippet
<a id="test" href="test.com">test.com</a>

// js snippet
<script>
  var href = document.getElementById('test').href
  console.log(href) // 显示 http://test.com
</script>
复制代码

 3. 不透明URI和分层URI

   不透明URI:scheme-specific-part组件不是以正斜杠(/)起始的,如mailto:fsjohnhuang@xxx.com。由于不透明URI无需进行分解操作,因此不会对scheme-specific-part组件进行有效性验证。

   分层URI:scheme-specific-part组件是以正斜杠(/)起始的,如http://fsjohnhuang.com。

      scheme-specific-part组件格式为: [//authority][path][?query] 

      [//authority] ,表示授权机构组件,以一对正斜杠(//)起始,可以基于主机(server-based)或注册(registry-based)(而基于注册相对基于主机的数目较少),并以正斜杠、问号或无后续字符作为authority组件的结束。而authority组件的具体格式为 [userinfo@]host[:port] 。

         [userinfo@] ,用户账号。

     host ,主机IP或域名。

     [:port] ,通信端口号,若省略则使用相应的scheme组件的默认端口号。

            示例: http://fsjohnhuang@github.com:80/ 

      [path] ,path组件表示根据authority组件识别资源的位置。path组件有一系列的路径片段(path segment)构成,路径片段间以正斜杠(/)作为分隔符。若第一个路径片段以正斜杠(/)起始则为绝对路径,否则称为相对路径。

      [?query] ,query组件用于识别要传递给资源的数据,用于影响资源的响应的行为。

 4. 标准化(Normalization)、解析化(Resolution)和相对化(Relativization)

  标准化(Normalization):其实就是去除path组件中当前层(.)和上一层(..)这些冗余字符。如z/../y标准化为y。

  解析化(Resolution):以URI A作为基本URI来和另外一个URI一同解析为一个新的标准URI。如http://fsjohnhuang.com作为基本URI和z/../y一同解析成http://fsjohnhuang.com/y。

  相对化(Relativization):相对化其实就是解析化的相反操作。如http://fsjohnhuang.com作为基本URI和http://fsjohnhuang.com/z来作相对化操作得到/z。

 

  到这里我们可能会认为这不就跟平常的网站地址一样吗?为啥大家叫网站地址为URL,而不是URI呢?

  互联网之父Tim Berners-Lee引入用于识别、定位和命名互联网资源的途径——URI、URL和URN。三者彼此关联,URI的范畴位于体系的顶层,URL和URN的范畴位于体系的底层。

             

  • URI:Uniform Resource Identifier,统一资源标识符;
  • URL:Uniform Resource Locator,统一资源定位符;
  • URN:Uniform Resource Name,统一资源名称。

  上图可知URL和URN必须是URI,但URI却不一定是URL或URN。

  URI仅仅是资源名称而已,知道了URI最多就是知道有这么一个名称的资源罢了,至于如何获取(与资源作交互)则是毫无头绪(不能定位或读取/写入资源),而这个资源名称是永久持有还是暂时持有也没有相应的规定,于是就有了URL和URN两个子集。

  首先URL和URN均继承了URI格式中的各组件,然后在这基础上进行了各自的扩展?

  URL

   URL = URI(scheme组件为部分已知的网络协议的URI子集) + 与scheme组件标识的网络协议匹配的协议处理器(URL Protocol Handler)

     1. URI的scheme组件在URL中称为protocol组件,一般http、https、ftp、file、data、jar等。

     2. URL Protocol Handler则是一种资源定位器和根据协议建立的约束规则与资源通信的读写机制,用于定位、读写资源。

         如:安装迅雷后点击ed2k的迅雷种子时则会自动打开迅雷下载界面,这是为什么呢?

              迅雷种子就是资源,而ed2k就是资源URL的protocol组件,而迅雷就是URL Protocol Handler。而protocol组件与URL Protocol Handler间的映射关系在windows下则存放在注册表中,而Ubuntu中存放在/usr/share/applications/.desktop中。

              windows7下

                ①. 快捷键“开始”+r 弹出运行输入框,输入regedit进入注册表;

         ②. 进入HKEY_CURRENT_USER/Software/Classes目录下;

             ③. ed2k目录下包含shell/Open/command目录,右侧窗口有一个条名称为URL Protocol的REG_SZ记录,表示这是一个URL Protocol记录(没有这一条记录也不会有影响)

               

                 ④. 点击command目录后,右侧窗口有一条REG_SZ类型记录,数据列为"C:\Program Files (x86)\Thunder Network\Thunder\Program\ThunderNewTask.exe" "%1" 表示ThunderNewTask.exe作为URL Protocol Handler,而%1则是传递给Handler处理的URL。

         ⑤. 其实ed2k中还少了一个DefaultIcon目录,该目录下有一个REG_SZ类型的记录,用于指定该类型协议文件的图标。

 

              ubuntu下

      在/usr/share/applications/.desktop文件下添加如下内容

复制代码
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Terminal=false
Exec=/usr/bin/cloudjerun -c %u
Name=tunesview
Comment=Small, easy-to-use program to access iTunesU media
Icon=/usr/share/icons/hicolor/scalable/apps/tunesview.svg
Categories=Application;Network;
MimeType=x-scheme-handler/cloudje;
复制代码

      Exec键值的占位符表:

复制代码
Add...  Accepts...
%f      a single filename.
%F      multiple filenames.
%u      a single URL.
%U      multiple URLs.
%d      a single directory. Used in conjunction with %f to locate a file.
%D      multiple directories. Used in conjunction with %F to locate files.
%n      a single filename without a path.
%N      multiple filenames without paths.
%k      a URI or local filename of the location of the desktop file.
%v      the name of the Device entry.
复制代码

     3. URL与资源地址关联,当资源位置变更后,URL也需要被修改。

 

  URN

   URN =  URI(scheme组件为部分已知的网络协议的URI子集) + 与scheme组件标识的网络协议匹配的协议处理器(URL Protocol Handler) + 持久性/地址无关性

   URN用于持久性地标识Internet资源,即使资源已经不存在或不可用时依然保持不变,通过实际的持久性策略实现资源位置发生变化也不用修改URI(地址无关性)。然而通过持久性策略还可以实现一条URN对应N条URI,如BT中的磁力链接(Magnet URI scheme)

   如:magnet:?xt=urn:btih:4D9FA761D69964B00DF0B3B0C9C1F968EA6C47D0&xt=urn:ed2k:7655dbacff9395e579c4c9cb49cbec0e&dn=bbb_sunflower_2160p_30fps_stereo_abl.mp4

 

   说了这么多是时候总结一下URI、URL和URN的关联和区别了!

   1. 首先URI是基础,URL和URN均属于URI;

   2. URL = URI(scheme组件为部分已知的网络协议的URI子集) + 与scheme组件标识的网络协议匹配的协议处理器(URL Protocol Handler);

   3. URN突出的是持久化,通过具体的持久化策略实现地址无关性。 URN =  URI(scheme组件为部分已知的网络协议的URI子集) + 与scheme组件标识的网络协议匹配的协议处理器(URL Protocol Handler) + 持久性/地址无关性。

   

四、java.net.URI类和java.net.URL类             

   java当中对URI和URL单独提供java.net.URI和java.netURL两个操作类。

   java.net.URI中主要提供以下功能

      1. 验证URI格式

构造函数URI(String str),若格式不正确则抛出URISyntaxException
URI.create(String str),若格式不正确则抛出unchecked的IllegalArgumentException

      2. 提取URI各组件

复制代码
getAuthority()
getFragment()
getHost()
getPath()
getPort()
getQuery()
getScheme()
getSchemeSpecificPart()
getUserInfo()
复制代码

      3. 标准化、解析化和相对化

复制代码
normalize(),,返回符合标准的URI新对象。如`x/y/../z/./q`->`x/z/q`
resolve(String/URI uri),进行反向解析,以入参作为相对URI,以resolve方法所属对象作为基本URI来得到一个新的标准的URI对象
relativize(URI uri),相对化操作,就是获取URI中的相对URI

实例:
URI uriBase = new URI("http://www.somedomain.com");
URI uriRelative = new URI("x/../y");
URI uriResolve = uriBase.resolve(uriRelative); // http://www.somedomain.com/y
URI uriRelativized = uriBase.relativize(uriResolve); // y
复制代码

      4. 将URI转成URL

URI#toURL(),将URI转换为URL。

      注意:不含任何搜索和读写资源的操作。

 java.net.URL中主要提供以下功能:

     URL类是依据URL Protocol Handler来处理URL字符串的,若没有相应的协议处理器则抛MalformedURLException。

     内置提供http、https、ftp、file和jar协议的URL Protocol Handler。而其他协议的处理器则需开发者自行继承URLStreamHandler来实现了。处理流程如下:

       1. 查看处理器缓存HashTable handlers,若存在缓存项则直接返回;

       2. 若缓存中没有则查看是否有URLStreamHandlerFactory实例,若存在则调用其createURLStreamHandler(String protocol)。默认情况下URLStreamHandlerFactory实例为null;

       3. 若2中返回null,则通过系统属性java.protocol.handler.pkgs获取以|分隔的包名列表,然后逐一检查是否存在继承了URLStreamHandler的<package>.<protocol>.Handler类,有则返回,无则继续遍历;

       4. 若3中遍历失败,则检查是否存在继承了URLStreamHandler的<system default package>.<protocol>.Handler的内置类。

       5. 上述均失败则抛出MalformedURLException。

    类URL中除了提供获取各组件的方法外,还提供了读写资源的方法如 InputStream openStream() 。下面我们通过URL类来读取t.txt文本文件的内容。

复制代码
class Main{
  static void main(String[] args) throws IOException, MalformedURLException{
    String path1 = "d:\\t.txt"
      , path2 = "file:/d:/t.txt";
    Main main = new Main();
    main.readByFr(path1);
    main.readByUrl(path2);
  }

  // 通过FileInputStream的写法
  void readByFr(String path) throws IOException{
    FileReader fr = new FileReader(path);
    try{
      int buf;
      while (-1 != buf){
        buf = fr.read();
        System.out.print((char)buf);
      }
    }finally{
        fr.close();
    }
  }

  // 通过URL的写法
   void readByURL(String path) throws MalformedURLException, IOException{
      URL url = new URL(path);
      InputStreamReader reader = new InputStreamReader(url.openStream());
    try{
        int buf;
        while (-1 != buf){
           buf = reader.read();
           System.out.print((char)buf);
      }
      }
      finally{
          reader.close();
     }
   }
}
复制代码

     

五、总结                              

  上述内容若有纰漏请大家指正,谢谢!

  尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4280369.html ^_^肥仔John  

 

六、参考                             

http://kb.cnblogs.com/page/90838/

https://msdn.microsoft.com/en-us/library/ms478653.aspx

http://www.cnblogs.com/wang726zq/archive/2012/12/11/UrlProtocol.html

http://stackoverflow.com/questions/16376429/ubuntu-custom-url-protocol-handler

http://www.ibm.com/developerworks/cn/xml/x-urlni.html

http://baike.baidu.com/link?url=agsiO-syltdQC_SlhSBThijAD3kSC4DVZcfnNPvO_KxGYOMCVqhiI58BDrn6tG06vohsH-evK1x7BqUj_wnR-a

JDK7 API

如果您觉得本文的内容有趣就扫一下吧!捐赠互勉!

分类: Java
1
0
« 上一篇: Java魔法堂:JVM的运行模式
» 下一篇: Java魔法堂:类加载机制入了个门
posted @ 2015-02-09 11:37 ^_^肥仔John 阅读( 5479) 评论( 3) 编辑 收藏
  
#1楼 2015-02-27 08:48 yanwushu  
很好的文章 谢谢分享
  
#2楼 2015-05-25 20:35 twocold0451  
  
#3楼 [ 楼主] 2015-05-28 12:52 ^_^肥仔John  
@ twocold0451
确实写错了,谢谢指正!
相关文章
|
2月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
74 4
|
29天前
|
Java 程序员
JAVA程序员的进阶之路:掌握URL与URLConnection,轻松玩转网络资源!
在Java编程中,网络资源的获取与处理至关重要。本文介绍了如何使用URL与URLConnection高效、准确地获取网络资源。首先,通过`java.net.URL`类定位网络资源;其次,利用`URLConnection`类实现资源的读取与写入。文章还提供了最佳实践,包括异常处理、连接池、超时设置和请求头与响应头的合理配置,帮助Java程序员提升技能,应对复杂网络编程场景。
49 9
|
29天前
|
人工智能 Java 物联网
JAVA网络编程的未来:URL与URLConnection的无限可能,你准备好了吗?
随着技术的发展和互联网的普及,JAVA网络编程迎来新的机遇。本文通过案例分析,探讨URL与URLConnection在智能API调用和实时数据流处理中的关键作用,展望其未来趋势和潜力。
43 7
|
4月前
|
Java
【思维导图】JAVA网络编程思维升级:URL与URLConnection的逻辑梳理,助你一臂之力!
【思维导图】JAVA网络编程思维升级:URL与URLConnection的逻辑梳理,助你一臂之力!
60 1
|
4月前
|
XML JSON 搜索推荐
【高手过招】JAVA网络编程对决:URL与URLConnection的高级玩法,你敢挑战吗?
【高手过招】JAVA网络编程对决:URL与URLConnection的高级玩法,你敢挑战吗?
72 0
|
29天前
|
Java 开发者
JAVA高手必备:URL与URLConnection,解锁网络资源的终极秘籍!
在Java网络编程中,URL和URLConnection是两大关键技术,能够帮助开发者轻松处理网络资源。本文通过两个案例,深入解析了如何使用URL和URLConnection从网站抓取数据和发送POST请求上传数据,助力你成为真正的JAVA高手。
47 11
|
29天前
|
JSON 安全 算法
JAVA网络编程中的URL与URLConnection:那些你不知道的秘密!
在Java网络编程中,URL与URLConnection是连接网络资源的两大基石。本文通过问题解答形式,揭示了它们的深层秘密,包括特殊字符处理、请求头设置、响应体读取、支持的HTTP方法及性能优化技巧,帮助你掌握高效、安全的网络编程技能。
51 9
|
29天前
|
JSON Java API
JAVA网络编程新纪元:URL与URLConnection的神级运用,你真的会了吗?
本文深入探讨了Java网络编程中URL和URLConnection的高级应用,通过示例代码展示了如何解析URL、发送GET请求并读取响应内容。文章挑战了传统认知,帮助读者更好地理解和运用这两个基础组件,提升网络编程能力。
47 5
|
2月前
|
存储 网络协议 前端开发
在 Java 中如何完全验证 URL
在 Java 中如何完全验证 URL
84 8
|
26天前
|
Java Spring
JAVA获取重定向地址URL的两种方法
【10月更文挑战第17天】本文介绍了两种在Java中获取HTTP响应头中的Location字段的方法:一种是使用HttpURLConnection,另一种是使用Spring的RestTemplate。通过设置连接超时和禁用自动重定向,确保请求按预期执行。此外,还提供了一个自定义的`NoRedirectSimpleClientHttpRequestFactory`类,用于禁用RestTemplate的自动重定向功能。