1、前言 html
過去一直搞不清什麼是URI什麼是URL,如今是時候好好弄清楚它們了!本文做爲學習筆記,以便往後查詢,如有紕漏請你們指正!java
2、從URI提及
git
1. 概念github
URI(Uniform Resource Identifier,統一資源標識符)以字符串來表示某種資源的統一資源標識。shell
格式爲: [scheme:]scheme-specific-part[#fragment] ubuntu
[scheme:]組件 ,URI的名稱空間標識。windows
scheme-specific-part組件 ,用於標識資源,內部格式由具體的 scheme 來決定。緩存
[#fragment]組件 ,井號(#)做爲fragment組件的起始字符,而fragment組件則用於聚焦到資源的某個部分。網絡
2. 絕對URI和相對URIapp
絕對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的範疇位於體系的底層。
上圖可知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) + 持久性/地址無關性。
4、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(); } } }
5、總結
上述內容如有紕漏請你們指正,謝謝!
尊重原創,轉載請註明來自:http://www.cnblogs.com/fsjohnhuang/p/4280369.html ^_^肥仔John
6、參考
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