背景介紹
從畢業到工作都一年多了,在這一年多的時間裡,我發現有的後臺程式設計師連 URL 的查詢引數都不知道,再加上最近使用 node 和 python 連線加密的 mongodb 時也遇到了點問題,就決定對我所知道的 URL 方面知識做一個總結。
何為URL
名詞解釋
URL 是 Uniform Resource Location 的縮寫,譯為“統一資源定位符”。通俗地說, URL 是 Internet 上用來描述資訊資源的字串,主要用在各種 www 客戶程式和伺服器程式上。採用URL可以用一種統一的格式來描述各種資訊資源,包括檔案、伺服器的地址和目錄等。
順便也提一下 URI 吧:
Web上可用的每種資源 - HTML文件、影象、視訊片段、程式等 - 由一個通過通 用資源標誌符(Universal Resource Identifier, 簡稱"URI")進行定位。
URI一般由三部分組成:
- 訪問資源的命名機制。
- 存放資源的主機名。
- 資源自身的名稱,由路徑表示。
URL 是 URI 的子集,但是平時的開發中我們只需要瞭解 URL 就可以了。
URL格式
以 http://test.com:8080/example/index.html
為例進行說明。
URL的格式由下列三部分組成:
- 第一部分是協議(或稱為服務方式),本例中為
HTTP 協議
。 - 第二部分是存有該資源的主機IP地址或域名(有時也包括埠號),本例中為
test.com:8080
。平時看到的都是域名,之後客戶端會通過DNS(域名系統) 查詢域名對應的 IP,然後根據IP和埠號進行伺服器的連線。稍後會對此進行詳細說明。 - 第三部分是主機資源的具體地址,如目錄和檔名等,本例中為
/example/index.html
。
URL 的語法
通用語法
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
- scheme: 協議,常見的有 http(80),https(443),mailto,ftp(21),rtsp,rtspu,file。
- user:使用者名稱。
- password: 密碼。
- host:主機。
- port: 埠。
- params: 引數。通常為
key=value
。 - query:查詢引數或查詢字串。
- frag: 片段(在瀏覽器中會被解析為
window.location.hash
)。
這只是通用語法,大多數的 URL 都只遵循了一部分而已,並不是每種URL都會有上面的所有資訊。
從上面的語法我們可以看出至少 :/@;?# 都是敏感字元,所以在其他引數中不能包含這些字元,如果含有敏感字元或者特殊字元,就需要使用對應的轉義字元,否則可能會發生不可預料的結果。
在開發過程中,容易在查詢引數中含有 敏感字元,所以查詢字串的值一般都需要使用 encodeURIComponent
進行編碼。
http(s)中的語法
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中的語法
檔案傳輸協議,可以用來從伺服器下載或上傳檔案。
基本格式:
ftp://<user>:<password>@<host>:<port>/<path>;<params>
示例:
ftp://ftpuser:123456.com@test.com:21/path/example
file中的語法
該協議常見於本地檔案於瀏覽器中開啟的場景,也可能是網路檔案系統或者其他一些檔案共享系統。這個我就不細說了,感覺沒啥可說的。
mongodb協議
常見於後臺程式連線 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,給我報的錯誤是連線超時,當時還納悶遠端的伺服器再慢也不至於吧???後來調整了超時時間,發現還是超時,而且一直在嘗試重新連線,就想到了可能是驗證失敗了,這個糾結了不少時間。
在瀏覽器中輸入URL後,執行的全部過程
整個流程如下:
- 域名解析;
- 發起TCP的3次握手;
- 建立TCP連線後發起http請求;
- 伺服器響應htp請求;
- 瀏覽器解析htm程式碼,並請求html程式碼中的資源(如js、css、圖片等);
- 斷開TCP連線;
- 瀏覽器對頁面進行渲染呈現給使用者。
其實,域名解析這個過程要是細說的話還是有點複雜的,總之有時候也是蠻耗時的,畢竟從 解析 這個用詞我們就能看出它一定是需要時間的?通過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系統的根目錄,然後在域名後面把檔案的路徑拼上去,還納悶怎麼就是訪問不到呢?
web伺服器的根目錄
常用的靜態伺服器是 nginx,設定一下靜態檔案的壓縮啦,快取啦,代理啦,識別裝置進行跳轉,圖片裁剪之類的,都是so easy,簡直就是我們大前端的標配嘛。
話雖然這麼說,現在的公司還是把我的前端檔案放在tomcat容器下,並沒有給我一個專屬的 nginx 伺服器,o(╥﹏╥)o。每次改完檔案我得先打包成壓縮包,發給後臺,他放到 tomcat 容器下,然後再上傳至伺服器,重啟容器,最後快取沒控制好,壓縮也沒搞。重啟之後還得懷疑一下我的檔案是不是發錯了,這檔案怎麼沒更新???其實用 nginx,再搭配 git 的 hooks,幾個命令列的事而已嘛,扯遠了,還是說說 web伺服器的根目錄吧。流行一點的web伺服器主要是 nginx, apache,tomcat,後兩個主要還是用於搭配後臺使用,不直接向外暴露介面的。這些靜態伺服器都會有一個配置用於設定 web 伺服器的根目錄,那麼這個根目錄的作用是什麼呢?就是控制客戶端能訪問到的頂級目錄。 比如根目錄是 www,是不能訪問 www 目錄以外的其他檔案的,只能訪問 www 的子目錄的各檔案。
參考連結
- 名詞解釋URL和URI
- 《HTTP權威指南》
- 在瀏覽器中輸入URL後,執行的全部過程