Java魔法堂:URI、URL(含URL Protocol Handler)和URN
轉(zhuǎn)載自? ?Java魔法堂:URI、URL(含URL Protocol Handler)和URN
一、前言
? 過去一直搞不清什么是URI什么是URL,現(xiàn)在是時(shí)候好好弄清楚它們了!本文作為學(xué)習(xí)筆記,以便日后查詢,若有紕漏請(qǐng)大家指正!
?
二、從URI說起 ?
?1. 概念
? URI(Uniform Resource Identifier,統(tǒng)一資源標(biāo)識(shí)符)以字符串來表示某種資源的統(tǒng)一資源標(biāo)識(shí)。
? 格式為:?[scheme:]scheme-specific-part[#fragment]?
??[scheme:]組件?,URI的名稱空間標(biāo)識(shí)。
??scheme-specific-part組件?,用于標(biāo)識(shí)資源,內(nèi)部格式由具體的?scheme?來決定。
??[#fragment]組件?,井號(hào)(#)作為fragment組件的起始字符,而fragment組件則用于聚焦到資源的某個(gè)部分。
?2. 絕對(duì)URI和相對(duì)URI
??絕對(duì)URI:以scheme組件起始的完整格式,如http://fsjohnhuang.cnblogs.com。表示以對(duì)標(biāo)識(shí)出現(xiàn)的環(huán)境無依賴的方式引用資源。
??相對(duì)URI:不以scheme組件起始的非完整格式,如fsjohnhuang.cnblogs.com。表示以對(duì)依賴標(biāo)識(shí)出現(xiàn)的環(huán)境有依賴的方式引用資源。
? 實(shí)例:當(dāng)前頁(yè)面地址為http://fsjohnuang.cnblogs.com
// html snippet <a id="test" href="test.com">test.com</a>// js snippet <script>var href = document.getElementById('test').hrefconsole.log(href) // 顯示 http://test.com </script>?3. 不透明URI和分層URI
? ?不透明URI:scheme-specific-part組件不是以正斜杠(/)起始的,如mailto:fsjohnhuang@xxx.com。由于不透明URI無需進(jìn)行分解操作,因此不會(huì)對(duì)scheme-specific-part組件進(jìn)行有效性驗(yàn)證。
? ?分層URI:scheme-specific-part組件是以正斜杠(/)起始的,如http://fsjohnhuang.com。
? ? ? scheme-specific-part組件格式為:?[//authority][path][?query]?
? ? ??[//authority]?,表示授權(quán)機(jī)構(gòu)組件,以一對(duì)正斜杠(//)起始,可以基于主機(jī)(server-based)或注冊(cè)(registry-based)(而基于注冊(cè)相對(duì)基于主機(jī)的數(shù)目較少),并以正斜杠、問號(hào)或無后續(xù)字符作為authority組件的結(jié)束。而authority組件的具體格式為?[userinfo@]host[:port]?。
? ? ?? ?[userinfo@]?,用戶賬號(hào)。
?host?,主機(jī)IP或域名。
?[:port]?,通信端口號(hào),若省略則使用相應(yīng)的scheme組件的默認(rèn)端口號(hào)。
? ? ? ? ? ? 示例:?http://fsjohnhuang@github.com:80/?
? ? ??[path]?,path組件表示根據(jù)authority組件識(shí)別資源的位置。path組件有一系列的路徑片段(path segment)構(gòu)成,路徑片段間以正斜杠(/)作為分隔符。若第一個(gè)路徑片段以正斜杠(/)起始則為絕對(duì)路徑,否則稱為相對(duì)路徑。
? ? ??[?query]?,query組件用于識(shí)別要傳遞給資源的數(shù)據(jù),用于影響資源的響應(yīng)的行為。
?4. 標(biāo)準(zhǔn)化(Normalization)、解析化(Resolution)和相對(duì)化(Relativization)
??標(biāo)準(zhǔn)化(Normalization):其實(shí)就是去除path組件中當(dāng)前層(.)和上一層(..)這些冗余字符。如z/../y標(biāo)準(zhǔn)化為y。
? 解析化(Resolution):以URI A作為基本URI來和另外一個(gè)URI一同解析為一個(gè)新的標(biāo)準(zhǔn)URI。如http://fsjohnhuang.com作為基本URI和z/../y一同解析成http://fsjohnhuang.com/y。
??相對(duì)化(Relativization):相對(duì)化其實(shí)就是解析化的相反操作。如http://fsjohnhuang.com作為基本URI和http://fsjohnhuang.com/z來作相對(duì)化操作得到/z。
?
? 到這里我們可能會(huì)認(rèn)為這不就跟平常的網(wǎng)站地址一樣嗎?為啥大家叫網(wǎng)站地址為URL,而不是URI呢?
? 互聯(lián)網(wǎng)之父Tim Berners-Lee引入用于識(shí)別、定位和命名互聯(lián)網(wǎng)資源的途徑——URI、URL和URN。三者彼此關(guān)聯(lián),URI的范疇位于體系的頂層,URL和URN的范疇位于體系的底層。
? ? ? ? ? ? ?
- URI:Uniform Resource Identifier,統(tǒng)一資源標(biāo)識(shí)符;
- URL:Uniform Resource Locator,統(tǒng)一資源定位符;
- URN:Uniform Resource Name,統(tǒng)一資源名稱。
? 上圖可知URL和URN必須是URI,但URI卻不一定是URL或URN。
? URI僅僅是資源名稱而已,知道了URI最多就是知道有這么一個(gè)名稱的資源罷了,至于如何獲取(與資源作交互)則是毫無頭緒(不能定位或讀取/寫入資源),而這個(gè)資源名稱是永久持有還是暫時(shí)持有也沒有相應(yīng)的規(guī)定,于是就有了URL和URN兩個(gè)子集。
? 首先URL和URN均繼承了URI格式中的各組件,然后在這基礎(chǔ)上進(jìn)行了各自的擴(kuò)展?
??URL
? ?URL = URI(scheme組件為部分已知的網(wǎng)絡(luò)協(xié)議的URI子集) + 與scheme組件標(biāo)識(shí)的網(wǎng)絡(luò)協(xié)議匹配的協(xié)議處理器(URL Protocol Handler)
? ? ?1. URI的scheme組件在URL中稱為protocol組件,一般http、https、ftp、file、data、jar等。
? ? ?2.?URL Protocol Handler則是一種資源定位器和根據(jù)協(xié)議建立的約束規(guī)則與資源通信的讀寫機(jī)制,用于定位、讀寫資源。
? ? ? ? ?如:安裝迅雷后點(diǎn)擊ed2k的迅雷種子時(shí)則會(huì)自動(dòng)打開迅雷下載界面,這是為什么呢?
? ? ? ? ? ? ? 迅雷種子就是資源,而ed2k就是資源URL的protocol組件,而迅雷就是URL Protocol Handler。而protocol組件與URL Protocol Handler間的映射關(guān)系在windows下則存放在注冊(cè)表中,而Ubuntu中存放在/usr/share/applications/.desktop中。
? ? ? ? ? ? ??windows7下
? ? ? ? ? ? ? ? ①. 快捷鍵“開始”+r 彈出運(yùn)行輸入框,輸入regedit進(jìn)入注冊(cè)表;
?? ?②. 進(jìn)入HKEY_CURRENT_USER/Software/Classes目錄下;
? ? ? ? ? ③. ed2k目錄下包含shell/Open/command目錄,右側(cè)窗口有一個(gè)條名稱為URL Protocol的REG_SZ記錄,表示這是一個(gè)URL Protocol記錄(沒有這一條記錄也不會(huì)有影響)
? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? ?④. 點(diǎn)擊command目錄后,右側(cè)窗口有一條REG_SZ類型記錄,數(shù)據(jù)列為"C:\Program Files (x86)\Thunder Network\Thunder\Program\ThunderNewTask.exe" "%1" 表示ThunderNewTask.exe作為URL Protocol Handler,而%1則是傳遞給Handler處理的URL。
? ? ⑤. 其實(shí)ed2k中還少了一個(gè)DefaultIcon目錄,該目錄下有一個(gè)REG_SZ類型的記錄,用于指定該類型協(xié)議文件的圖標(biāo)。
?
? ? ? ? ? ? ? ubuntu下
在/usr/share/applications/.desktop文件下添加如下內(nèi)容
[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與資源地址關(guān)聯(lián),當(dāng)資源位置變更后,URL也需要被修改。
? URN
? ?URN =??URI(scheme組件為部分已知的網(wǎng)絡(luò)協(xié)議的URI子集) + 與scheme組件標(biāo)識(shí)的網(wǎng)絡(luò)協(xié)議匹配的協(xié)議處理器(URL Protocol Handler) + 持久性/地址無關(guān)性
? ?URN用于持久性地標(biāo)識(shí)Internet資源,即使資源已經(jīng)不存在或不可用時(shí)依然保持不變,通過實(shí)際的持久性策略實(shí)現(xiàn)資源位置發(fā)生變化也不用修改URI(地址無關(guān)性)。然而通過持久性策略還可以實(shí)現(xiàn)一條URN對(duì)應(yīng)N條URI,如BT中的磁力鏈接(Magnet URI scheme)。
? ?如:magnet:?xt=urn:btih:4D9FA761D69964B00DF0B3B0C9C1F968EA6C47D0&xt=urn:ed2k:7655dbacff9395e579c4c9cb49cbec0e&dn=bbb_sunflower_2160p_30fps_stereo_abl.mp4
?
? ?說了這么多是時(shí)候總結(jié)一下URI、URL和URN的關(guān)聯(lián)和區(qū)別了!
? ?1. 首先URI是基礎(chǔ),URL和URN均屬于URI;
? ?2.?URL = URI(scheme組件為部分已知的網(wǎng)絡(luò)協(xié)議的URI子集) + 與scheme組件標(biāo)識(shí)的網(wǎng)絡(luò)協(xié)議匹配的協(xié)議處理器(URL Protocol Handler);
? ?3. URN突出的是持久化,通過具體的持久化策略實(shí)現(xiàn)地址無關(guān)性。?URN =??URI(scheme組件為部分已知的網(wǎng)絡(luò)協(xié)議的URI子集) + 與scheme組件標(biāo)識(shí)的網(wǎng)絡(luò)協(xié)議匹配的協(xié)議處理器(URL Protocol Handler) + 持久性/地址無關(guān)性。
? ?
四、java.net.URI類和java.net.URL類
? ?java當(dāng)中對(duì)URI和URL單獨(dú)提供java.net.URI和java.netURL兩個(gè)操作類。
? ?java.net.URI中主要提供以下功能:
? ? ? 1. 驗(yàn)證URI格式
構(gòu)造函數(shù)URI(String str),若格式不正確則拋出URISyntaxException URI.create(String str),若格式不正確則拋出unchecked的IllegalArgumentException? ? ? 2. 提取URI各組件
getAuthority() getFragment() getHost() getPath() getPort() getQuery() getScheme() getSchemeSpecificPart() getUserInfo()? ? ? 3. 標(biāo)準(zhǔn)化、解析化和相對(duì)化
normalize(),,返回符合標(biāo)準(zhǔn)的URI新對(duì)象。如`x/y/../z/./q`->`x/z/q` resolve(String/URI uri),進(jìn)行反向解析,以入?yún)⒆鳛橄鄬?duì)URI,以resolve方法所屬對(duì)象作為基本URI來得到一個(gè)新的標(biāo)準(zhǔn)的URI對(duì)象 relativize(URI uri),相對(duì)化操作,就是獲取URI中的相對(duì)URI實(shí)例: 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轉(zhuǎn)成URL
URI#toURL(),將URI轉(zhuǎn)換為URL。? ? ? 注意:不含任何搜索和讀寫資源的操作。
java.net.URL中主要提供以下功能:
? ? ?URL類是依據(jù)URL Protocol Handler來處理URL字符串的,若沒有相應(yīng)的協(xié)議處理器則拋MalformedURLException。
? ? ?內(nèi)置提供http、https、ftp、file和jar協(xié)議的URL Protocol Handler。而其他協(xié)議的處理器則需開發(fā)者自行繼承URLStreamHandler來實(shí)現(xiàn)了。處理流程如下:
? ? ? ?1. 查看處理器緩存HashTable handlers,若存在緩存項(xiàng)則直接返回;
? ? ? ?2. 若緩存中沒有則查看是否有URLStreamHandlerFactory實(shí)例,若存在則調(diào)用其createURLStreamHandler(String protocol)。默認(rèn)情況下URLStreamHandlerFactory實(shí)例為null;
? ? ? ?3. 若2中返回null,則通過系統(tǒng)屬性java.protocol.handler.pkgs獲取以|分隔的包名列表,然后逐一檢查是否存在繼承了URLStreamHandler的<package>.<protocol>.Handler類,有則返回,無則繼續(xù)遍歷;
? ? ? ?4. 若3中遍歷失敗,則檢查是否存在繼承了URLStreamHandler的<system default package>.<protocol>.Handler的內(nèi)置類。
? ? ? ?5. 上述均失敗則拋出MalformedURLException。
? ? 類URL中除了提供獲取各組件的方法外,還提供了讀寫資源的方法如?InputStream openStream()?。下面我們通過URL類來讀取t.txt文本文件的內(nèi)容。
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();}} }? ? ?
五、總結(jié)
? 上述內(nèi)容若有紕漏請(qǐng)大家指正,謝謝!
?
六、參考
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
總結(jié)
以上是生活随笔為你收集整理的Java魔法堂:URI、URL(含URL Protocol Handler)和URN的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于TCP/IP必须知道的几个基础问题
- 下一篇: Java8学习笔记(1) -- 从函数式