浏览器速度与网站服务器有关吗,HTTP协议,浏览器缓存和网站速度优化

在计算机和网络的世界里,小到CPU,大到Internet,缓存无处不在。个人认为,缓存策略主要解决两个问题,第一个是解决不同设备IO速度不同的资源等待问题,第二个是解决相同资源重复传送的资源浪费问题。例如最常提到的CPU的三级缓存,就是为了解决CPU计算速度快,而读取内存速度慢导致CPU等待的问题。而我们上网的过程过,浏览器对已经请求的资源进程缓存,则属于缓存策略解决的第二个问题。本文主要分析一下HTTP协议,浏览器缓存和网站速度优化。

http-cache.jpg

HTTP属于应用层协议,由请求包和响应包组成,都包括HTTP头信息(header)和主体信息(body)。在响应信息中,主体信息就是用浏览器看到的内容;请求包中,一般只有POST类型的请求才包含主体信息。web浏览器一般有两种缓存方式,一种是缓存body,通过头部信息对服务器和本地信息进行比对, 如果符合某些特征,服务器返回304 Not Modified,浏览器接受返回,并加载之前返回的内容,整个过程如下图:

HTTP-caching-last-modified.png

当浏览器第一次请求信息,服务器发送如下返回头:

HTTP/1.1 200 OK

Connection:keep-alive

Content-Type:text/html

Last-Modified:Thu, 04 Mar 2015 01:47:20 GMT

….

这个返回头中有一个非常重要的信息Last-Modified,它告诉浏览器次资源上次更改的时间,浏览器接受这个信息,并缓存下来,当第二次请求这个资源的时候,浏览器自动加上一条If-Modified-Since:Thu, 04 Mar 2015 01:47:20 GMT,服务器接收这个请求, 并比对资源更改时间和这个时间,如果这段时间内没法发生变化,则只返回头部信息,而不返回HTML实体:

HTTP/1.1 304 Not Modified

Connection:keep-alive

Content-Type:text/html

Last-Modified:Thu, 04 Mar 2015 01:47:20 GMT

由于html的内容一般比较大,这样一来,就大大增加了网站的加载速度,减少了宽带的消耗。

Last-Modified的信息只能精确到秒,如果一秒之内文件资源作出了更改,浏览器则不会实时的加载到新的内容,人们又发明了另一个标签对Etag和If-None-Match,和上面的工作原理类似,Web服务器通过Etag标签发送资源的某种hash值,浏览器接收之后,下次访问则通过If-None-Match把缓存到的hash值发送给服务器,如果文件内容发生了变化,则前后两次的hash只不一样,服务器就发送最新的文件内容,否则返回304 Not Modified。

下面这段代码是利用Etag和Modifed给PHP页面做缓存的例子:

class Cache304{

public $content;

private $contlen;

private $etag;

private $modified;

//设置过期时间,单位秒

public $expiresenconds;

public function __construct($ex){

(int) $this->expiresenconds=$ex;

$this->etag=isset($_SERVER["HTTP_IF_NONE_MATCH"])?$_SERVER["HTTP_IF_NONE_MATCH"]:false;

$this->modified=isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])?$_SERVER["HTTP_IF_MODIFIED_SINCE"]:false;

ob_start(array($this,'get_content'));

}

public function get_content($html){

$this->content=$html;

$this->contlen=strlen($html);

return $html;

}

public function init(){

register_shutdown_function(array($this,'show'));

}

public function show(){

ob_end_clean();

//Etag验证

if($this->etag == md5($this->content)){

header("HTTP/1.1 304 Not Modified");

header("Vary:etag");

exit();

}else{

//注意发送Etag必须要发送Content-Length标签

header("Etag:".md5($this->content));

header("Content-Length:$this->contlen");

header("Last-Modified:".gmdate("D, d M Y H:i:s")." GMT");

echo $this->content;

exit();

}

//Last-Modified验证

if($this->modified && (strtotime(gmdate("D, d M Y H:i:s")." GMT") - strtotime($this->modified) < $this->expiresenconds)){

header("HTTP/1.1 304 Not Modified");

header("Last-Modified:".$this->modified);

header("Vary:Modified");

exit();

}else{

header("Etag:".md5($this->content));

header("Content-Length:$this->contlen");

header("Last-Modified:".gmdate("D, d M Y H:i:s")." GMT");

echo $this->content;

exit();

}

}

}

$a = new Cache304(3600);

$a->init();

//假设一下是原本要输出的内容

echo "你好
";

echo "今天是2015年3月5日
";

echo "欢迎来到我的网站";

?>

运行这段代码,当第二次访问时,服务器确实返回的是304 Not Modified。当强制刷新再次访问时,发现服务器返回的状态码又变成了200,这是因为,当我们强制刷新访问时,浏览器不再发送”If-Modified-Since”和”If-None-Match”的请求头,并且还在请求头里面加了一个”Pragma:no-cache”标识(Chrome 39.0.2171.95 m),这样是为了通知服务器发送最新的内容。

上面说到的缓存,实际上只在发送HTML内容这个地方实现了缓存,该有的业务逻辑服务器上都有运行,客户端和服务器一样建立了TCP链接,网站速度虽然快了,但是对服务器的压力却没有多大的改善。HTTP提供另外一种直接读取本地缓存的方式,这种方式下浏览器直接读取缓存,而不向服务器发送请求,返回的状态码是200 OK(from cache),如下图:

200-ok-from-cache.jpg

HTTP提供两个头标签Cache-Control和Expires来控制本地缓存,Cache-Control可以通过max-age来指定过期时间,Expires指定未来一个过期时间的,具体的用法可以点击这里。需要注意的是,对于直接读取的本地缓存,只适用新打开的页面,浏览器刷新,强制刷新,一般都会重新请求新数据。

对了一个优秀的网站来说,采用多级缓存很有必要,不断能够缩短网站的打开时间,还能节省网站资源,服务更多人群。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值