使用 CDN
CDN: Content Delivery Network ,内容分发网络。由于网络的差异性,尤其是我国南北电信网通的差异,网络速度容易成为用户访问慢的因素。而 CDN 提供商则会通过在不通的网络环境做镜像来解决网络的差异性,尽量使各种网络环境下的用户能够流畅的拉取页面。需要注意的是,CDN 基本上只用来分发静态内容。
文章中只大概列举了使用 CDN 的大网站的情况以及美国提供 CDN 的服务商,没有太多价值,但是 CDN 这个概念,对不少 web 开发者来说确实比较陌生。
指定页面过期时间
http 协议中允许指定 Expires 来说明某个文件的过期时间。当一个浏览器跟服务器请求到一个文件以后,在该文件过期之前,它可以无需跟浏览器请求而直接使用浏览器自己请求过的该文件的 cache(浏览器自己的 cache) 。所以,对浏览器可能多次请求的文件指定过期时间,能够有效减少浏览器对服务器的请求。一般需要考察用户的浏览器习惯等因素。
Expires 是指定文件具体的过期时间,在 http 1.0 中引入了一个可以覆盖该 Expires 的 Cache-Control 头的 max-age ,可以指定文件的有效秒数。不过使用 apache 的 mod_expires 可以直接根据文件创建或其他时间加一定长度的时间达到同样的目的。
需要注意的是,有时候更新了网页需要强制用户更新 cache ,对样式表以及 js 脚本等,通常可以通过改变请求文件的路径或者带参数来清除 cache 。
gzip 压缩
gzip 压缩能够大大的减少纯文本内容在网络中的传输量—减少网络流量。在 http 1.1 中加入了压缩的支持。
浏览器请求包头: Accept-Encoding: gzip, deflate ,服务器回包头:Content-Encoding: gzip 。书中说 gzip 压缩比 deflate 要好,这点不得而知 — — apache 2 使用 deflate, 而 apache 1 使用 gzip,在其他文章中看到过说 deflate 在磁盘 io 等方面表现更好 。( deflate 同时是一种压缩算法)
压缩通常只针对文本类型的文件,对图片等不需要进行压缩,另外由于小文件(1-2k 以下)压缩没有太大的意义,所以通常还可以通过设置 mod_gzip_minimum_file_size 来设置压缩的最小文件。默认最小值是 0.5k — 没有说什么模块的默认设置,估计应该是 apache 的 mod_gzip 和 mod_deflate 。
在 apache 1 使用的 mod_gzip 中,可以通过两个指令指定压缩的或者不压缩的类型,比如:
mod_gzip_item_include file \.js$
mod_gzip_item_include mime ^application/x-javascript$
mod_gzip_item_include file \.css$
mod_gzip_item_include mime ^text/css$
mod_gzip 可以把压缩的内容放在磁盘或者内存中,具体可以看 mod_gzip_can_negotiate 和 mod_gzip_update_static 两个指令。
apache 2 中使用 mod_deflate 大概配置:AddOutputFilterByType DEFLATE text/html text/css application/x-javascript
和 mod_gzip 不一样,mod_deflate 可以指定压缩级别。
进行压缩有一个通过代理服务器上网的浏览器问题:在一个代理服务器上网的环境下,所有浏览器请求到的页面都是该 proxy 第一次 cache 该页面时取到的格式:压缩或者未压缩的。这时候如果该环境下有非 cache 中压缩状态的请求,就可能出问题了。一般来说,可以通过服务器在发包中发送这个头:Vary: Accept-Encoding 。
一般默认情况下,压缩的模块都会发送这个包头。
内容压缩确实有些边缘问题。现在大多数浏览器都是支持压缩的,一般如果浏览器发包说支持,服务器可以信任该包的声明。但是目前对 IE5.5 和 IE6 等版本的浏览器确实存在已知的 bug ,可以参见 http://support.microsoft.com/kb/313712/en-us and http://support.microsoft.com/kb/312496/en-us 。书中又说可有通过设置浏览器白名单,似乎仍然没有解决 bug 的问题:
# mod_gzip
mod_gzip_item_include reqheader "User-Agent: MSIE [6-9]"
mod_gzip_item_include reqheader "User-Agent: Mozilla/[5-9]"
# mod_deflate
BrowserMatch ^MSIE [6-9] gzip
BrowserMatch ^Mozilla/[5-9] gzip
把样式表放在最上面
因为一般浏览器都是把一个 html 文件从上到下进行渲染,但是在很多浏览器里,如果在 html 文件尾放一个样式,可能会阻止浏览器的这种渲染方式,浏览器为了防止某些元素的样式被重复定义,可能会在尾部的样式表载入之后才会渲染整个页面,就会出现所谓的空白屏(Blank white screen)现象。无论在 html 文件中的位置如何, @import 方式载入外部 css 文件也可能有类似的问题。一般来说,样式都放在 head 标签中,也就是 body 标签之前。
RFC 中有建议浏览器在解释 html 的过程中,对一个域名同时进行两个请求。
把脚本放在最下面
跟上面类似,一般浏览器都是从上到下渲染 html ,但是遇到 js 时,它会阻塞对后面的 html 的渲染。因此如果这个 js 不是用来渲染页面,它就会实际延迟页面的渲染。
关于并行下载,前面说提了,rfc 中建议对同一个域名(主机,hostname)同时进行两个请求(注意还不是两个连接)。虽然 IE 可以通过修改注册表, firefox 可以在 about:config 中修改,但是并不能依赖这个。值得注意的是,对 http 1.0 的请求, firefox 允许同时进行八个请求。提到 Yahoo 的经验,一般使用 2 个 hostname 比 1 个或者 4 个, 10 个可以获得更好的性能。
因为脚本中可能 document.write 等方式修改 html 结构,所以一般浏览器处理都是遇到脚本事阻塞其他请求(当然也无法渲染后面的页面元素)——不管是否是对多个 hostname 的。另外一方面来说,同时请求多个 js ,他们之前可能会有互相的冲突,或者破坏他们之间的依赖性。