前端要給力之:URL應該有多長?

來源:互聯網
上載者:User

URL到底應該有多長?我為什麼要提這個問題呢?有許多最佳化指南裡都寫著:要盡量減小COOKIE、縮短URL,以及儘可能地使用GET請求等等,以便最佳化WEB頁面的請求和裝載。但是,這種所謂“儘可能”、“盡量”只是定性的描述,定量的來看,要縮短到多少個位元組才算少呢?

 

就以我們某次首頁的改版中,通過http analyzers我看到幾個有趣的.js檔案的URL,是這樣的:
https://static.alipay.net/build/js/app/tracker.js?v=083 
https://static.alipay.net/build/js/home/home.js?t=20101012 
https://static.alipay.net/build/js/pa/alieditcontrol-update.js?t=20101012 
https://static.alipay.net/javascript/arale_v1.0.js  
https://static.alipay.net/min/?b=javascript&f=arale/lang/aspect.js,arale/lang/md5.js,arale/lang/uri.js,arale/lang/tmpl.js,arale/lang/date.js,arale/lang/number.js,arale/http/jsonp.js,arale/http/ajax.js,arale/http/core.js,arale/event/event-chain.js,arale/class/declare.js,arale/fx/animator.js,aralex/widget.js,aralex/tplwidget.js,aralex/view.js,aralex/tab/tab.js,aralex/dropdown/dropdown.js,aralex/slider/slider.js,aralex/slider/switchslider.js 
https://static.alipay.net/build/js/app/tracker.js?v=083
https://static.alipay.net/build/js/home/home.js?t=20101012
https://static.alipay.net/build/js/pa/alieditcontrol-update.js?t=20101012
https://static.alipay.net/javascript/arale_v1.0.js
https://static.alipay.net/min/?b=javascript&f=arale/lang/aspect.js,arale/lang/md5.js,arale/lang/uri.js,arale/lang/tmpl.js,arale/lang/date.js,arale/lang/number.js,arale/http/jsonp.js,arale/http/ajax.js,arale/http/core.js,arale/event/event-chain.js,arale/class/declare.js,arale/fx/animator.js,aralex/widget.js,aralex/tplwidget.js,aralex/view.js,aralex/tab/tab.js,aralex/dropdown/dropdown.js,aralex/slider/slider.js,aralex/slider/switchslider.js

注意最後一條。嗯,不要驚訝,的確是這樣長的URL,確切的長度是443bytes。但這是長了呢?還是不算長呢?

要知道以IE為例,可以處理的URL長度為2048 bytes,也就是說,反正~~無論如何,IE是能處理的。其實,一般瀏覽器也沒問題,所以,“正確性”是沒問題。所以,接下來我們要說的是效率。

 
一、TCP/IP協議中的包頭問題

在TCP/IP網路中,底層協議是一回事,應用程式層協議又是一回事。所以作為應用程式層協議的HTTP,自身可以傳輸多大的內容,以及如何傳輸(例如HTTP包一般以48K為界限,超過48K時會出現應用程式層的分包,即所謂的multipart)這些都是由應用程式層來約定的。而在底層協議中,鏈路層與傳輸層對“傳多大的包”有各自的約定。簡單的說,傳輸層約定了IP資料包的MSS(最大分段尺寸),鏈路層約定了MTU(傳輸單元最大值)。如果一個IP資料包的大小超過MTU(即MSS+TCP前序+IP前序>MTU),則在鏈路層會將IP資料包拆成多個資訊包傳輸。

 

MSS與不同的傳輸環境相關,有兩個推薦值。一般來說,
 - 目標地址非本地地址(與源地址在不同一個網段)時,MSS預設值通常是536;否則,
 - MSS預設值通常為1460。
MTU與網路環境相關,也有兩個推薦值。一般來說,
 - 串口為576位元組;
 - 乙太網路為1500位元組。

MTU/MSS的兩種推薦值中都有40個位元組的差異,即是(TCP前序+IP前序)的一般值,該值以120 bytes為上限(20+20位元組的IP/TCP頭部;40+40位元組IP/TCP可選頭部)。所以在複雜的網路環境中,應用程式層的網路通訊協定可用的單個資料包的大小,最佳值應小於536-80=456位元組,盡量限制在1460-80 = 1380位元組以內。這樣的限制,是綜合考慮傳輸層與鏈路層協議的結果。不過一些常見的建議中,也會用536/1460這兩個值,與這裡的討論沒有太本質的差異。我只是強調,如果我們要一個“足夠最佳化的請求”,那麼極限值應該是多少?

 
二、HTTP協議中的包頭問題

那麼,現在來到HTTP這個應用程式層協議。一個HTTP請求由頭部與資料區構成,對於HTTP GET請求來說,可以只有頭部而沒有資料區,原因是HTTP頭部的內容如下(頭部需要以2個連續斷行符號換行結束):
---------  
GET (...) HTTP/1.1  
Accept:*/*  
Referer:http://www.alipay.net/  
Accept-Language:zh-cn  
User-Agent: (...)  
Accept-Encoding:gzip, deflate  
Host:static.alipay.net  
Connection:Keep-Alive  
Cookie: (...)  
--------- 
---------
GET (...) HTTP/1.1
Accept:*/*
Referer:http://www.alipay.net/
Accept-Language:zh-cn
User-Agent: (...)
Accept-Encoding:gzip, deflate
Host:static.alipay.net
Connection:Keep-Alive
Cookie: (...)
---------

這裡的GET (...)可以跟著一個完整的GET請求的URL,而GET請求的參數也都放在這個URL上,因此可以不需要有單獨的資料區。在上述的這個HTTP請求中,某些特定的用戶端可能會多幾個或少幾個http head field,但通常欄位都會比較短。我們僅以這個例子來說明,那麼這個“預設的(不完整的)HTTP頭”用掉了多少位元組呢?

答案是184位元組。不過還需要強調,Referer與當前正在瀏覽的網址直接相關,例如當前正在瀏覽的頁面是500位元組長的URL,那麼當前網頁上的超連結點擊時Referer欄位都會填上這個500位元組的URL,網頁中過長的URL會使得點擊超連結時消耗更多的傳輸,這裡也是一例了。

那麼不討論Referer欄位的影響,僅以上述為例,我們能用的最佳值,就只剩下了456-184=272位元組了。這272位元組會有三個地方使用,就是上面標為(...)的三個地方:GET、User-Agent和Cookie。User-Agent這個欄位與瀏覽器相關,不同的瀏覽器以及該瀏覽器處理不同的作業系統環境時,都會出現不同。在JS以及伺服器上的統計軟體中,也常常使用這個欄位來判斷瀏覽器環境,例如OS、版本等。這個欄位的值有時候會比較長,以我當前的機器為例,該值為:
---------
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; QQWubi 108; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET CLR 1.1.4322; .NET CLR 3.5.21022; .NET4.0C; .NET4.0E)
---------
佔用了274位元組。也就是說,事實上理想環境下的使用456位元組就已經不夠用了。按此前討論的,我們可以退而求其次:
 - 使用536位元組的邊界值,即不考慮80位元組的tcp/ip可選頭部。

此外,需要強調的是User-Agent長度的可變性,例如上面的“EmbeddedWB……”等64位元組在一般的電腦中可能就沒有,這是一個第三方組件。同樣的,也可能因為其它的瀏覽器環境(例如傲遊)導致這個欄位更長。基於這個事實,我仍以本例中的這一特殊情況來做分析。

以536位元組為例,我們事實上還有78位元組可用,因此在這裡我們將最佳化的第一等級設為:70位元組。建議公司可以根據伺服器端收集的資料取一個平衡值。

 

三、COOKIE耗用可以降到0

現在,Cookie是消耗最大的地方,以我當前的機器為例,該值有幾種情況(對於不同的協議與域,是不一樣的):

(1) 對於首頁http://www.alipay.net/,值有49位元組:
ali_apache_id=12.1.11.70.1275978936200.5; lastpg=

(2) 對於http://*.alipay.net/,值有171位元組:
ali_apache_id=12.1.11.70.1275978936200.5; ali_apache_sid=12.1.46.46.128998714836.4|1289988948; ALIPAYJSESSIONID=bYWcn4Wq0Z5FBCoHzfpn2f1XxDAmBepay; ali_apache_tracktmp=uid=

(3) 對於https://static.alipay.net/,值有307位元組:
cna=AKaaAhYBhU0BAeMdAHlnHNcd; ali_apache_id=169.17.198.19.1272623861747.7; payMethod=directPay; _tb_order=38016166656317; defaultBank=ICBC; __utma=22931947.260433774.1277279158.1277279158.1282287558.2; __utmz=22931947.1282287558.2.2.utmcsr=life.alipay.net|utmccn=(referral)|utmcmd=referral|utmcct=/index.php

(4) 對於http(s)://img.alipay.net/,值有379位元組:
apay_id=159588238.127262386236866.128979461890689.1289969142342368.137; cna=AKaaAhYBhU0BAeMdAHlnHNcd; ali_apache_id=169.17.198.19.1272623861747.7; payMethod=directPay; _tb_order=38016166656317; defaultBank=ICBC; __utma=22931947.260433774.1277279158.1277279158.1282287558.2; __utmz=22931947.1282287558.2.2.utmcsr=life.alipay.net|utmccn=(referral)|utmcmd=referral|utmcct=/index.php

(5) 其它情況。

為什麼在2、3、4情況下出現了cookie使用的暴增呢?事實上,3、4兩種情況雖然略有差異,但產生問題的根源與情況2是完全一致的。所以後文僅以情況2為例。跟蹤其http request過程可知:
 - 請求首頁時,伺服器端返回了四個set-cookie應答。

 

這四個應答(http response head)如下:
--------

Set-Cookie:ali_apache_sid=10.2.46.46.128998714836.4|1289988948; path=/; domain=.alipay.net
Set-Cookie:JSESSIONID=A8CE523AEA03E2C990D6796D6BAEC81E; Path=/
Set-Cookie:ALIPAYJSESSIONID=bYWcn4Wq0Z5FBCoHzfpn2f1XxDAmBepay; Domain=.alipay.net; Path=/
Set-Cookie:ali_apache_tracktmp=uid=; Domain=.alipay.net; Path=/

--------

所以在此後的所有http請求中,都將使用如前例(3)中的171位元組的cookie。但是,顯然的,至少有以下幾種情況這些cookie是無意義的:
 - 如果訪問的是重新導向頁面,包括返回Status Code:302的重新導向,以及html頁面中使用http-meta的重新導向;
 - 如果訪問的頁面是被緩衝的,例如返回Status Code:304的“Not Modified”;
 - 如果訪問的頁面是靜態、無需識別cookie的,例如static.alipay.net中的.img、.js和.css檔案等。

顯然,我們在img、static中的圖片或其它靜態資源是可以被緩衝的,而且無論是緩衝還是第一次存取,cookie值都完全沒有意義。對於靜態頁面(.html)來說,如果我們不是要通過http server來統計分析靜態頁面的訪問情況,那麼這些cookie也是不需要的。所以,對於這些資源、內容,我們應該強調的使這些cookie不被發送,或盡量少的使用(對於部分的.html靜態頁,我們可能僅僅需要用於分析使用者訪問鏈的session id)。

最佳化cookie的方式很簡單:將這些靜態資源部署在不以.alipay.net為domain的伺服器/組裡,或使用其它的獨立網域名稱。這種情況下,對於特定的——當然也是最大量的一部分——資源,COOKIE耗用可以降到0。

 
四、縮短url

總算來到我們的正題:URL可以有多長?通過前面的分析,我們仍然還有70字書可以用,即使在特定條件下,我們需要給一些頁面訪問留下track資料(例如session),那麼我們仍然有40~50個位元組可以用。不過,僅此而已,我們離本文最開始提到的443 bytes仍然有相當相當長的距離。

 

但我們真的需要這麼長的URL嗎?

答案是不需要,我們完全可以縮短URL。例如前面的例子,我們原始的URL的get部分是:
---------  
/min?b=javascript&f=arale/lang/aspect.js,arale/lang/md5.js,arale/lang/uri.js,arale/lang/tmpl.js,arale/lang/date.js,arale/lang/number.js,arale/http/jsonp.js,arale/http/ajax.js,arale/http/core.js,arale/event/event-chain.js,arale/class/declare.js,arale/fx/animator.js,aralex/widget.js,aralex/tplwidget.js,aralex/view.js,aralex/tab/tab.js,aralex/dropdown/dropdown.js,aralex/slider/slider.js,aralex/slider/switchslider.js  
--------- 
---------
/min?b=javascript&f=arale/lang/aspect.js,arale/lang/md5.js,arale/lang/uri.js,arale/lang/tmpl.js,arale/lang/date.js,arale/lang/number.js,arale/http/jsonp.js,arale/http/ajax.js,arale/http/core.js,arale/event/event-chain.js,arale/class/declare.js,arale/fx/animator.js,aralex/widget.js,aralex/tplwidget.js,aralex/view.js,aralex/tab/tab.js,aralex/dropdown/dropdown.js,aralex/slider/slider.js,aralex/slider/switchslider.js
---------

仔細觀察,它的意思其實是
---------
/min?b=javascript&f=...
---------

欄位f後面的,其實是arale這個指令碼項目中的一些靜態資源的拼接。在伺服器端,min這個程式根據參數"b=javascript&f=..."將一些指令碼片段拼接成一個單獨.js檔案並返回到瀏覽器,如果沒有變化,則直接返回Status Code:304。

那麼,事實上我們每次請求的“f=...”欄位後面的參數區塊將會是完全一樣的。或者,即使在不同的情況下要求拼接的檔案清單不一樣,也僅有相當有限的組合。這使我們自然的想到一個東西:求和。用這種方式對上述的字串求一個key(例如hash、md5、crc),然後我們就可以用這個唯一key來尋找拼接後的.js內容——這也意味著min程式不需要每次都拼接文本。這樣一來,上面的URL可以變成(以對f欄位後的396位元組求crc32為例):
---------
/min?b=javascript&f=313466DB
---------
考慮到不同的版本管理:
---------
/min?b=javascript&v=0.9b&f=313466DB
---------

現在,我們將URL控制在了一個相當小的規模,而且加上了版本管理和內容的有效性驗證,需要的情況下,伺服器端的min程式也可以做動態產生以及緩衝。這些改造與我們原始的需求並沒有任何的衝突。重要的是,我們成功地將get請求控制在了35位元組,餘留的空間完全滿足我們

整體最佳化的需要:第一等級的最佳化,70位元組!

 
五、技術成熟性與價值

1、twritter中早就使用這樣的技術了。

2、與arale項目類似的,YQL(Yahoo! Query Language)項目也有類似的需求,因此他們將“在URL上傳入一個sql”通過上述技術變成了一個短名,例如:
http://y.ahoo.it/iHQ8c0sv
相當於
http://developer.yahoo.com/yql/console/?q=select%20woeid%20from%20geo.places%20where%20text%3D%22san%20francisco%2C%20ca%22

3、微軟還“傻傻說不清楚”,所以你看他們的官網很慢。^^.

4、當我們有條件將http頭部減小到456位元組以下時,應儘力為之。例如WangWang因為有獨立用戶端,所以可以定製http request head,以縮減User-Agent等欄位。

5、當我們總是從瀏覽器端發出最小化的HTTP請求時,網路總是可以最快速的將請求提交到伺服器,無需等待多個包並組合。這在慢速網路,以及存在大量丟包的網路中效果將為極為明顯。簡單地說,如果有人在區域網路中用迅雷或BT,那麼最小化HTTP請求將會使網頁的瀏覽體驗提升得相當相當明顯。

6、我們應該做指令碼等靜態資源的版本管理了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.