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

 

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

  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个连续回车换行结束):

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

  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、我们应该做脚本等静态资源的版本管理了。

前端要给力之:URL应该有多长?的更多相关文章

  1. 前端回答从输入URL到页面展示都经历了些什么

    浏览器和服务器涉及大量网络通信内容,此处做了弱化介绍,作为前端主要关注第四部分.一. 网络环境保障我们先假定我们访问的URL为www.abc.com并且地址不在局域网内:首先我们所处的局域网的总路由应 ...

  2. 前端学HTTP之URL

    × 目录 [1]URI [2]URL语法 [3]字符[4]编码方法 前面的话 一般地,URL和URI比较难以区分.接下来,本文以区分URL和URI为引子,详细介绍URL的用法 URI与URL的区别 U ...

  3. 【前端】从输入URL到页面加载完成的过程中都发生了什么事情

    把URL分割成几个部分:协议(http, https).网络地址(xxx.xxx.xxx.xxx).资源路径(/xxx/xxx.xx).端口号(默认80). 如果地址不是一个IP地址,通过DNS(域名 ...

  4. 003-pro ant design 前端权限处理-支持URL参数的页面

    前天需要增加MD5引用 https://www.bootcdn.cn/blueimp-md5/ 1.修改权限文件(CheckPermissions.js)使用自定义权限 2.配置异常页面 2.1.创建 ...

  5. 前端为什么要对url进行编码

    为什么要对url进行编码 url有规范,在参数值中出现&字符会截断参数 url中文的问题,编码客转换为英文 也是第一种情况,url中有个参数值是url,传输的时候会出现错误 例1 有这样一串参 ...

  6. 前端性能----从输入URL开始到返回数据的中间经历过程

    这是一个古老的问题,即我们输入URL后按下回车到网页测呈现都发生了什么? 首先来看一张图: 表示了数据从源端到目的端的封装和拆解过程 预处理URL URL格式:  以http为例: http://ww ...

  7. 前端要给力之:语句在JavaScript中的值

    文件夹 文件夹 问题是语句有值吗 那么说你骗我咯 有啥米用呢 研究这个是不是闲得那个啥疼 ES5ES6有什么差异呢 结论是ES6是改了规则但更合理 最后不不过if语句 这两天在写语言精髓那本书的第三版 ...

  8. 【经验分享】URL链接地址最长是多少?

    近期在做一个Hot Fix,其中有个界面在IE6下超链接无法打开,经查是链接地址太长,2161个字节,已经超出ie6,7的长度限制,现把发现此问题的过程分享给大家. ===过程===== 1.万恶的i ...

  9. 【基础进阶】URL详解与URL编码

    作为前端,每日与 URL 打交道是必不可少的.但是也许每天只是单纯的用,对其只是一知半解,随着工作的展开,我发现在日常抓包调试,接口调用,浏览器兼容等许多方面,不深入去理解URL与URL编码则会踩到很 ...

随机推荐

  1. 深度学习基础系列(十一)| Keras中图像增强技术详解

    在深度学习中,数据短缺是我们经常面临的一个问题,虽然现在有不少公开数据集,但跟大公司掌握的海量数据集相比,数量上仍然偏少,而某些特定领域的数据采集更是非常困难.根据之前的学习可知,数据量少带来的最直接 ...

  2. Microsoft Office Access

    Microsoft Office Access各版本下载地址:http://www.accessoft.com/download.html 简介 access(微软发布的关联式数据库管理系统)一般指M ...

  3. CentOS通过光盘启动救援数据

    (1).CentOS6 1)首先确保实体机有光盘,虚拟机有光盘镜像.并通过BIOS设置从光盘启动,实体机请通过提示进入BIOS,虚拟机请找到上方菜单中虚拟机-->电源-->打开电源时进入固 ...

  4. Chrome 无痕模式

    Windows.Linux 或 Chrome 操作系统:按 Ctrl + Shift + n

  5. 查看shell 版本

    cat /etc/shells 查看本机支持的解释器: echo $SHELL 当我们直接使用./a.sh来执行这个脚本的时候,如果没有shebang,那么它就会默认用$SHELL指定的解释器,否则就 ...

  6. android无后缀二进制执行文件替代apk实现程序功能

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha android无后缀二进制执行文件替代apk实现程序功能 实现将data/Android ...

  7. zookeeper【3】服务发现

    服务发现:指对集群中的服务上下线做统一管理,每个工作服务器都可以作为数据的发布方,向集群注册自己的基本信息,而让某些监控服务器作为订阅方,订阅工作服务器的基本信息.当工作服务器的基本信息改变时,如服务 ...

  8. Python编码规则

    1. 命名规则 1.1 变量名.包名.模块名 变量名通常有字母.数字和下划线组成,且首字母必须是字母或下划线,并且不能使用python的保留字:包名.模块名通常用小写字母 1.2 类名.对象名 类名首 ...

  9. PYQT控件使用

    QtGui.QComboBox .addItem(string)#添加字符串项到Item.addItems(list)#添加列表或元组元素到Item.clear()#清除所有Item.clearEdi ...

  10. 华为S5300系列升级固件S5300SI-V100R006C00SPC800.cc

    这个固件附带了web,V100R005可以直接升级到这个版本,但没什么必要,因为V100R005本身可以直接升级到V200. 升级小插曲: 1.升级的使用使用Windows,不要用Mac或者Linux ...