前端要给力之:URL应该有多长?
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
注意最后一条。嗯,不要惊讶,的确是这样长的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 (...)可以跟着一个完整的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=... ---------
字段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应该有多长?的更多相关文章
- 前端回答从输入URL到页面展示都经历了些什么
浏览器和服务器涉及大量网络通信内容,此处做了弱化介绍,作为前端主要关注第四部分.一. 网络环境保障我们先假定我们访问的URL为www.abc.com并且地址不在局域网内:首先我们所处的局域网的总路由应 ...
- 前端学HTTP之URL
× 目录 [1]URI [2]URL语法 [3]字符[4]编码方法 前面的话 一般地,URL和URI比较难以区分.接下来,本文以区分URL和URI为引子,详细介绍URL的用法 URI与URL的区别 U ...
- 【前端】从输入URL到页面加载完成的过程中都发生了什么事情
把URL分割成几个部分:协议(http, https).网络地址(xxx.xxx.xxx.xxx).资源路径(/xxx/xxx.xx).端口号(默认80). 如果地址不是一个IP地址,通过DNS(域名 ...
- 003-pro ant design 前端权限处理-支持URL参数的页面
前天需要增加MD5引用 https://www.bootcdn.cn/blueimp-md5/ 1.修改权限文件(CheckPermissions.js)使用自定义权限 2.配置异常页面 2.1.创建 ...
- 前端为什么要对url进行编码
为什么要对url进行编码 url有规范,在参数值中出现&字符会截断参数 url中文的问题,编码客转换为英文 也是第一种情况,url中有个参数值是url,传输的时候会出现错误 例1 有这样一串参 ...
- 前端性能----从输入URL开始到返回数据的中间经历过程
这是一个古老的问题,即我们输入URL后按下回车到网页测呈现都发生了什么? 首先来看一张图: 表示了数据从源端到目的端的封装和拆解过程 预处理URL URL格式: 以http为例: http://ww ...
- 前端要给力之:语句在JavaScript中的值
文件夹 文件夹 问题是语句有值吗 那么说你骗我咯 有啥米用呢 研究这个是不是闲得那个啥疼 ES5ES6有什么差异呢 结论是ES6是改了规则但更合理 最后不不过if语句 这两天在写语言精髓那本书的第三版 ...
- 【经验分享】URL链接地址最长是多少?
近期在做一个Hot Fix,其中有个界面在IE6下超链接无法打开,经查是链接地址太长,2161个字节,已经超出ie6,7的长度限制,现把发现此问题的过程分享给大家. ===过程===== 1.万恶的i ...
- 【基础进阶】URL详解与URL编码
作为前端,每日与 URL 打交道是必不可少的.但是也许每天只是单纯的用,对其只是一知半解,随着工作的展开,我发现在日常抓包调试,接口调用,浏览器兼容等许多方面,不深入去理解URL与URL编码则会踩到很 ...
随机推荐
- Error after SQL Server 2012 installation: Login Failure for "SQL Server Integration Services 11.0" SSIS service
When you install SQL Server 2012 and you try to connect to SSIS services, you cannot due to that the ...
- Form与ModelForm-下拉框或者多选注意//及字段补充
一.Form 设计一张普通model表: class UserInfo(models.Model): name = models.CharField(verbose_name='员工姓名', max_ ...
- 下拉框搜索插件chosen
{% load staticfiles %} <!DOCTYPE html> <html lang="en"> <head> <meta ...
- Django的orm中get和filter的不同
Django的orm框架对于业务复杂度不是很高的应用来说还是不错的,写起来很方面,用起来也简单.对于新手来说查询操作中最长用的两个方法get和filter有时候一不注意就会犯下一些小错误.那么今天就来 ...
- Python进阶篇:文件系统的操作
通过一个例子来熟悉文件的基本操作:创建文件,读取文件,修改文件,删除文件,重命名文件,判断文件是否存在 ''' 编写可供查询的员工信息表--学号 姓名 年龄 班级 1. 提供格式化查询接口 2. 允许 ...
- 【动态规划+Floyd】OpenJudge3368
OpenJudge上刷水都不会了……这题居然写了一个半小时…… [题目大意] 诸葛亮要征服N城市.然而,City-X在击败City-2,City-3……City-x-1后击败.关羽,张飞,赵云,每个人 ...
- vijos p1768 数学
链接:点我 预处理:b[i][j]表示a[1] ... a[j]中比a[i]小的数的数量. 设 int get_lower_count(int b[], int l, int r) { return ...
- UVA 10177 Sqr/Rects/Cubes/Boxes?
Problem J (2/3/4)-D Sqr/Rects/Cubes/Boxes? Input: standard input Output: standard output Time Limit: ...
- hdoj 5182 PM2.5 排序
PM2.5 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Descr ...
- codecombat js
#1 // Move to the gem. // Don't touch the walls! // Type your code below. this.moveRight(); this.mov ...