從畢業到工做都一年多了,在這一年多的時間裏,我發現有的後臺程序員連 URL 的查詢參數都不知道,再加上最近使用 node 和 python 鏈接加密的 mongodb 時也遇到了點問題,就決定對我所知道的 URL 方面知識作一個總結。javascript
URL 是 Uniform Resource Location 的縮寫,譯爲「統一資源定位符」。通俗地說, URL 是 Internet 上用來描述信息資源的字符串,主要用在各類 www 客戶程序和服務器程序上。採用URL能夠用一種統一的格式來描述各類信息資源,包括文件、服務器的地址和目錄等。css
順便也提一下 URI 吧:html
Web上可用的每種資源 - HTML文檔、圖像、視頻片斷、程序等 - 由一個經過通 用資源標誌符(Universal Resource Identifier, 簡稱"URI")進行定位。前端
URI通常由三部分組成:java
URL 是 URI 的子集,可是平時的開發中咱們只須要了解 URL 就能夠了。node
以 http://test.com:8080/example/index.html
爲例進行說明。python
URL的格式由下列三部分組成:linux
HTTP 協議
。test.com:8080
。平時看到的都是域名,以後客戶端會經過DNS(域名系統) 查詢域名對應的 IP,而後根據IP和端口號進行服務器的鏈接。稍後會對此進行詳細說明。/example/index.html
。<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
nginx
key=value
。window.location.hash
)。這只是通用語法,大多數的 URL 都只遵循了一部分而已,並非每種URL都會有上面的全部信息。git
從上面的語法咱們能夠看出至少 :/@;?# 都是敏感字符,因此在其餘參數中不能包含這些字符,若是含有敏感字符或者特殊字符,就須要使用對應的轉義字符,不然可能會發生不可預料的結果。 在開發過程當中,容易在查詢參數中含有 敏感字符,因此查詢字符串的值通常都須要使用 encodeURIComponent
進行編碼。
http://test.com:8080/user/index.html?id=1&nickName=test#/list
在瀏覽器中被解析後的格式爲:
{
protocol: 'http:', // 協議
host: 'test.com:8080', // 主機名或域名,帶端口號
hostname: 'test.com', // 主機名或域名,不帶端口號
port: '', // 端口號,http默認80,https默認443
path: '/user/index.html', // 路徑
query: '?id=1&nickName=test', // 查詢字符串
hash: '#list', //片斷或者哈希,
}
複製代碼
注意: #後面的東西都不會從客戶端傳到服務器。
在地址欄中改變 # 後的字符串時,頁面並不會刷新,可是會出發 hashchange 事件,不少前端路由的 hash 模式就是根據這種特性實現的。而改變出了frag(hash)
以外的東西都會致使瀏覽器刷新,由於此時至關於向服務器發出了一個新的請求。
文件傳輸協議,能夠用來從服務器下載或上傳文件。
基本格式:
ftp://<user>:<password>@<host>:<port>/<path>;<params>
示例:
ftp://ftpuser:123456.com@test.com:21/path/example
該協議常見於本地文件於瀏覽器中打開的場景,也多是網絡文件系統或者其餘一些文件共享系統。這個我就不細說了,感受沒啥可說的。
常見於後臺程序鏈接 mongodb 數據庫。雖然咱們常見的包都是用對象格式來鏈接數據庫的,可是最後都會被轉化爲字符串形式的。
基本格式:
mongodb://<user>:<password>@<host>:<port>/<path>?<query>
示例:
mongodb://test:123456@127.0.0.1:27017/novel?authSource=admin
該字符串表示以 mongodb 協議,用戶名爲test,密碼爲123456,數據庫dbName爲novel,驗證的數據庫爲admin,鏈接至127.0.0.1主機的27017端口。
注意:如mongodb服務器沒有開啓加密,須要去掉查詢參數,不然會鏈接失敗。若開啓了加密,authSource的值必須和前方的user和password相對應。,不然用戶驗證頁沒法鏈接。 我用的thinkjs,一開始沒有配置 authSource,給我報的錯誤是鏈接超時,當時還納悶遠程的服務器再慢也不至於吧???後來調整了超時時間,發現仍是超時,並且一直在嘗試從新鏈接,就想到了多是驗證失敗了,這個糾結了很多時間。
整個流程以下:
其實,域名解析這個過程要是細說的話仍是有點複雜的,總之有時候也是蠻耗時的,畢竟從 解析 這個用詞咱們就能看出它必定是須要時間的?經過DNS會將域名解析爲 IP,以後會根據 IP 和 端口鏈接服務器。
若是咱們直接用IP訪問服務器,就能夠節省一部分時間,但仍是不建議你們這麼作,由於若是更換了服務器的話,域名能夠解析到另外一個IP,能夠在瀏覽器端保留相應的數據,而IP就不行了。還有就是,域名的可訪問性和可讀性可比IP強多了。
上面的大部分都只適用於靜態服務器,若是是動態服務器的話,它會有本身的一套解析規則,可是大體上也是相同的,最大的區別可能仍是動態服務器的動態路由吧(前端路由如今也支持動態路由了)。
下面主要就說一下動態服務器相對於靜態服務器的特殊點:
好比定義一個獲取某我的的信息的接口,它的路徑爲:{ path: '/user/:id' }
當訪問 /user/1?name=test
時,該接口將被框架解析爲:
{
params: {
id: 1,
},
query: {
name: 'test',
}
}
複製代碼
若是是靜態路由的話,只能使用 /user?id=1&name=test
這種方式來傳遞參數了,從這能夠看出動態路由在必定程度上仍是比靜態路由有一點優點的;並且動態路由看上去更優雅。
可是若是後臺對路由的定義很差,前端傳過去的參數爲空的話,動態路由就會變成 /user/
,訪問到的接口就不是 /user/:id
這個路由,而是 /user/
這個接口了,後臺差找不到該路由,直接就返回 404 或者自定義的錯誤了。
我接觸過的後臺框架有 ThinkPHP 和 thinkjs, 這兩個仍是比較類似的,它們都有一個特性就是可以進行路由重寫,好比在定義好的路由以後加上後綴,若是設置 ext: '.html'
,那麼訪問 /user/1.html
時將被解析爲 /user/:id
,在那些先後端還未分離的公司,這個應該是主要的頁面輸出方式了(記得不知道從哪看到的這樣好像有利於SEO優化?)。
因此之後在看到 http://test.com/user/1.html
這樣的 URL的時候,就不能再單純的認爲它必定指向服務器的某個靜態文件,它如今也多是通過模板渲染以後的一個響應。
說了點動態服務器的,那就再說一點靜態服務器的吧,由於我遇到的一個後臺,在前端上傳文件後,直接把文件存儲到linux系統的根目錄,而後在域名後面把文件的路徑拼上去,還納悶怎麼就是訪問不到呢?
經常使用的靜態服務器是 nginx,設置一下靜態文件的壓縮啦,緩存啦,代理啦,識別設備進行跳轉,圖片裁剪之類的,都是so easy,簡直就是咱們大前端的標配嘛。
流行一點的web服務器主要是 nginx, apache,tomcat,後兩個主要仍是用於搭配後臺使用,不直接向外暴露接口的。這些靜態服務器都會有一個配置用於設置 web 服務器的根目錄,那麼這個根目錄的做用是什麼呢?就是控制客戶端能訪問到的頂級目錄。 好比根目錄是 www,是不能訪問 www 目錄之外的其餘文件的,只能訪問 www 的子目錄的各文件。