Heim  >  Artikel  >  Web-Frontend  >  前端要给力之:URL应该有多长?_html/css_WEB-ITnose

前端要给力之:URL应该有多长?_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-24 11:57:321137Durchsuche

URL到底应该有多长?我为什么要提这个问题呢?有许多优化指南里都写着:要尽量减小COOKIE、缩短URL,以及尽可能地使用GET请求等等,以便优化WEB页面的请求和装载。但是,这种所谓“尽可能”、“尽量”只是定性的描述,定量的来看,要缩短到多少个字节才算少呢?

 

就以我们某次首页的改版中,通过http analyzers我看到几个有趣的.js文件的URL,是这样的:

[xhtml]  view plaincopy

  1. https://static.alipay.net/build/js/app/tracker.js?v=083  
  2. https://static.alipay.net/build/js/home/home.js?t=20101012  
  3. https://static.alipay.net/build/js/pa/alieditcontrol-update.js?t=20101012  
  4. https://static.alipay.net/javascript/arale_v1.0.js  
  5. 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个连续回车换行结束):

[xhtml]  view plaincopy

  1. ---------  
  2. GET (...) HTTP/1.1  
  3. Accept:*/*  
  4. Referer:http://www.alipay.net/  
  5. Accept-Language:zh-cn  
  6. User-Agent: (...)  
  7. Accept-Encoding:gzip, deflate  
  8. Host:static.alipay.net  
  9. Connection:Keep-Alive  
  10. Cookie: (...)  
  11. ---------  

 

这里的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部分是:

[xhtml]  view plaincopy

  1. ---------  
  2. /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  
  3. ---------  

 

仔细观察,它的意思其实是 --------- /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字节以下时,应尽力为之。例如旺旺因为有独立客户端,所以可以定制http request head,以缩减User-Agent等字段。

5、当我们总是从浏览器端发出最小化的HTTP请求时,网络总是可以最快速的将请求提交到服务器,无需等待多个包并组合。这在慢速网络,以及存在大量丢包的网络中效果将为极为明显。简单地说,如果有人在局域网中用迅雷或BT,那么最小化HTTP请求将会使网页的浏览体验提升得相当相当明显。

6、我们应该做脚本等静态资源的版本管理了。

 

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn