首页 > 代码库 > web缓冲机制

web缓冲机制

最近项目里用到了Html5缓存机制,于是很想搞清楚 浏览器缓存,HTML5离线缓存,还有项目中用到的 CDN缓存 这三部分的关系以及更新机制。看了一堆关于HTML5缓存机制的文章,各有所长,各有疏漏。因此本人想在此做一总结,本文假设读者对基本的HTML5缓存应用已有所了解,因此不再详述概念,可以将本文当做释疑汇总吧。

以下部分内容引用自网络。

一、Web缓存的类型

在Web应用领域,Web缓存大致可以分为以下几种类型:

数据库数据缓存

Web应用,特别是SNS类型的应用,往往关系比较复杂,数据库表繁多,如果频繁进行数据库查询,很容易导致数据库不堪重荷。为了提供查询的性能,会将查询后的数据放到内存中进行缓存,下次查询时,直接从内存缓存直接返回,提供响应效率。比如常用的缓存方案有memcached等。  

服务器端缓存

 代理服务器缓存

代理服务器是浏览器和源服务器之间的中间服务器,浏览器先向这个中间服务器发起Web请求,经过处理后(比如权限验证,缓存匹配等),再将请求转发到源服务器。代理服务器缓存的运作原理跟浏览器的运作原理差不多,只是规模更大。可以把它理解为一个共享缓存,不只为一个用户服务,一般为大量用户提供服务,因此在减少相应时间和带宽使用方面很有效,同一个副本会被重用多次。常见代理服务器缓存解决方案有Squid等,这里不再详述。

CDN缓存

CDN(Content delivery networks)缓存,也叫网关缓存、反向代理缓存。CDN缓存一般是由网站管理员自己部署,为了让他们的网站更容易扩展并获得更好的性能。浏览器先向CDN网关发起Web请求,网关服务器后面对应着一台或多台负载均衡源服务器,会根据它们的负载请求,动态将请求转发到合适的源服务器上。虽然这种架构负载均衡源服务器之间的缓存没法共享,但却拥有更好的处扩展性。从浏览器角度来看,整个CDN就是一个源服务器,从这个层面来说,本文讨论浏览器和服务器之间的缓存机制,在这种架构下同样适用。

浏览器端缓存

浏览器缓存根据一套与服务器约定的规则进行工作,在同一个会话过程中会检查一次并确定缓存的副本足够新。如果你浏览过程中,比如前进或后退,访问到同一个图片,这些图片可以从浏览器缓存中调出而即时显现。 

这里解释一下,HTML5时代所谓“浏览器”缓存有两部分:browser cache (浏览器缓存)和app cache(HTML5的离线应用缓存)后面会详细介绍。

Web应用层缓存

应用层缓存指的是从代码层面上,通过代码逻辑和缓存策略,实现对数据,页面,图片等资源的缓存,可以根据实际情况选择将数据存在文件系统或者内存中,减少数据库查询或者读写瓶颈,提高响应效率。

二、浏览器缓存与HTML5离线缓存

了解了Web缓存的组成,现在把重点放在项目中的HTML5缓存机制上。我们都知道HTML5没生出来以前,浏览器自身也是有缓存机制的,所以我得搞清楚现在它和HTML5离线缓存之间到底是如果调用和更新的。

缓存清单

引用清单文件

要启用某个应用的应用缓存,请在文档的 html 标记中添加 manifest 属性:

<html manifest="example.appcache">

  ...

</html>

您应在要缓存的网络应用的每个页面上都添加 manifest 属性。如果网页不包含 manifest 属性,浏览器就不会缓存该网页(除非清单文件中明确列出了该属性)。这就意味着用户浏览的每个包含manifest 的网页都会隐式添加到应用缓存。因此,您无需在清单中列出每个网页。

manifest 属性可指向绝对网址或相对路径,但绝对网址必须与相应的网络应用同源。清单文件可使用任何文件扩展名,但必须以正确的 MIME 类型提供

<html manifest="http://www.example.com/example.mf">

  ...

</html>

清单文件必须以 text/cache-manifest MIME 类型提供,且必须以UTF-8编码。您可能需要向网络服务器或 .htaccess 配置添加自定义文件类型。

例如,要在 Apache 中提供此 MIME 类型,请在您的配置文件中添加下面一行内容:(扩展名自定义)

AddType text/cache-manifest .appcache

 

另外,Web开发时,也可直接在web.xml中指定MIME类型:

<mime-mapping>

            <extension>manifest</extension>

            <mime-type>text/cache-manifest</mime-type>

</mime-mapping>

 

清单文件结构

CACHE MANIFEST

# the above line is required

 

# this is a comment

# there can be as many of these anywhere in the file

# they are all ignored

  # comments can have spaces beforethem

  # but must be alone on the line

 

# blank lines are ignored too

 

# these are files that need to be cached they can either be listed

# first, or a "CACHE:" header could be put before them, as isdone

# lower down.

images/sound-icon.png

images/background.png

# note that each file has to be put on its own line

# here is a file for the online whitelist -- it isn‘t cached, and

# references to this file will bypass the cache, always hitting the

# network (or trying to, if the user is offline).

NETWORK:

comm.cgi

# here is another set of files to cache, this time just the CSS file.

CACHE:

style/default.css

# static.html will be served if main.py is inaccessible# offline.jpg willbe served in place of all images in images/large/# offline.html will be servedin place of all other .html filesFALLBACK:/main.py /static.htmlimages/large/images/offline.jpg*.html /offline.html

 

以“#”开头的行是注释行,但也可用于其他用途。应用缓存只在其清单文件发生更改时才会更新。例如,如果您修改了图片资源或更改了 JavaScript 函数,这些更改不会重新缓存。您必须修改清单文件本身才能让浏览器刷新缓存文件。使用生成的版本号、文件哈希值或时间戳创建注释行,可确保用户获得您的软件的最新版。您还可以在出现新版本后,以编程方式更新缓存

CACHE:

这是条目的默认部分。系统会在首次下载此标头下列出的文件(或紧跟在 CACHE MANIFEST 后的文件)后显式缓存这些文件。

NETWORK:

此部分下列出的文件是需要连接到服务器的白名单资源。无论用户是否处于离线状态,对这些资源的所有请求都会绕过缓存。可使用通配符(这个用法很讲究)。

FALLBACK:

此部分是可选的,用于指定无法访问资源时的后备网页。其中第一个 URI 代表资源,第二个代表后备网页。两个 URI 必须相关,并且必须与清单文件同源。可使用通配符。

请注意:这些部分可按任意顺序排列,且每个部分均可在同一清单中重复出现。

请注意:系统会自动缓存引用清单文件的 HTML 文件。因此您无需将其添加到清单中,但我们建议您这样做。

请注意:HTTP 缓存标头以及对通过 SSL 提供的网页设置的缓存限制将被替换为缓存清单。因此,通过 https 提供的网页可实现离线运行。

这里有一种特例需要解释一下:

CACHE MANIFEST

FALLBACK:

/ /offline.html

NETWORK:

*

 

上面的代码定义了一个匹配所有的错误页offline.html,离线访问时,所有在同一域名下的页面都会应用到它。同时这段代码也指定了白名单通配符状态为打开(Open),意思是访问其他域名下的资源不会被阻塞。

白名单通配符*,有两种状态(是否使用) Open和 Blocking。

       Open状态意思是所有未在CACHE中声明的URL都会被隐式认为属于NETWORK;

      Blocking状态意思是所有未明确地在manifest文件中声明的URL都会被认为不可用(unavailable.),都将不能访问。

使用了NETWORK的通配符“*”,只要你有网络连接,任何不在应用程序缓存中的资源将仍然从原网络地址下载,这对开放的应用程序非常重要。这意味着浏览器可以获取各种资源,即使它们和你的应用程序不在同一个域名下。如果没有此通配符,当你在线时,我们设想支持离线的应用将会行为诡异——它将不会加载任何不同域名下的资源。

事件流

当用户访问一个声明了manifest的页面时,浏览器会尝试获取一份manifest文件的拷贝,如果发现有更新,则下载该manifest文件中声明的所有资源并重新缓存它们。

同时,这将触发一系列事件,如下所示:

Event name

Interface

Fired when...

Next events

checking

Event

The user agent is checking for an update, or attempting to download the manifest for the first time.This is always the first event in the sequence.

noupdate,downloading,obsolete,error

noupdate

Event

The manifest hadn‘t changed.

Last event in sequence.

downloading

Event

The user agent has found an update and is fetching it, or is downloading the resources listed by the manifest for the first time.

progress,error,cached,updateready

progress

ProgressEvent

The user agent is downloading resources listed by the manifest. The event object‘stotal attribute returns the total number of files to be downloaded. The event object‘sloaded attribute returns the number of files processed so far.

progress,error,cached,updateready

cached

Event

The resources listed in the manifest have been downloaded, and the application is now cached.

Last event in sequence.

updateready

Event

The resources listed in the manifest have been newly redownloaded, and the script can useswapCache() to switch to the new cache.

Last event in sequence.

obsolete

Event

The manifest was found to have become a 404 or 410 page, so the application cache is being deleted.

Last event in sequence.

error

Event

The manifest was a 404 or 410 page, so the attempt to cache the application has been aborted.

Last event in sequence.

The manifest hadn‘t changed, but the page referencing the manifest failed to download properly.

A fatal error occurred while fetching the resources listed in the manifest.

The manifest changed while the update was being run.

The user agent will try fetching the files again momentarily.

这些事件都是可取消的,它们的目的是让浏览器显示下载进度信息。但如果你要显示自己的更新UI,那么取消这些事件会避免显示冗余的用户进度信息。

更新机制

应用在离线后将保持缓存状态,除非发生以下某种情况:

1.    用户清除了浏览器对您网站的数据存储。

2.    清单文件经过修改。请注意:更新清单中列出的某个文件并不意味着浏览器会重新缓存该资源。清单文件本身必须进行更改。

3.    应用缓存通过编程方式进行更新。

缓存状态

window.applicationCache 对象是对浏览器的应用缓存的编程访问方式。其 status 属性可用于查看缓存的当前状态:

var appCache = window.applicationCache;

switch (appCache.status) {

  case appCache.UNCACHED: //UNCACHED == 0

    return ‘UNCACHED‘;

    break;

  case appCache.IDLE: // IDLE == 1

    return ‘IDLE‘;

    break;

  case appCache.CHECKING: //CHECKING == 2

    return ‘CHECKING‘;

    break;

  case appCache.DOWNLOADING: //DOWNLOADING == 3

    return ‘DOWNLOADING‘;

    break;

  case appCache.UPDATEREADY:  // UPDATEREADY == 4

    return ‘UPDATEREADY‘;

    break;

  case appCache.OBSOLETE: //OBSOLETE == 5

    return ‘OBSOLETE‘;

    break;

  default:

    return ‘UKNOWN CACHE STATUS‘;

    break;

};

 

要以编程方式更新缓存,请先调用 applicationCache.update()。此操作将尝试更新用户的缓存(前提是已更改清单文件)。最后,当applicationCache.status 处于UPDATEREADY 状态时,调用 applicationCache.swapCache() 即可将原缓存换成新缓存。

var appCache = window.applicationCache;

appCache.update(); // Attempt to update the user‘s cache.

...

 

if (appCache.status == window.applicationCache.UPDATEREADY) {

  appCache.swapCache();  // The fetch was successful, swap in the newcache.

}

 

请注意:以这种方式使用 update() 和 swapCache() 不会向用户提供更新的资源。此流程只是让浏览器检查是否有新的清单、下载指定的更新内容以及重新填充应用缓存。因此,还需要对网页进行两次重新加载才能向用户提供新的内容,其中第一次是获得新的应用缓存,第二次是刷新网页内容。

好消息是,您可以避免重新加载两次的麻烦。要使用户更新到最新版网站,可设置监听器,以监听网页加载时的 updateready 事件:

// Check if a new cache is available on page load.

window.addEventListener(‘load‘, function(e) {

 

 window.applicationCache.addEventListener(‘updateready‘, function(e) {

    if(window.applicationCache.status == window.applicationCache.UPDATEREADY) {

      // Browser downloaded a newapp cache.

      // Swap it in and reload thepage to get the new hotness.

     window.applicationCache.swapCache();

      if (confirm(‘A new version ofthis site is available. Load it?‘)) {

        window.location.reload();

      }

    } else {

      // Manifest didn‘t changed.Nothing new to server.

    }

  }, false);

 

}, false);

 

web缓冲机制