离线缓存与客户端存储总结

离线检测

可以使用navigator.onLine属性来检测

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>判断设备是否能上网</title>
    </head>
    <body>
    <script type="text/javascript"> if(navigator.onLine){ console.log(navigator.onLine);//true 表示设备可以上网 alert("可以上网"); }else{ console.log(navigator.onLine);//false 表示设备不可以上网 alert("不可以上网"); } </script>
    </body>
</html>

除了navigator.onLine之外,还可以使用HTML5中的online和offline事件

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>online和offline</title>
    </head>
    <body>
    <script type="text/javascript" src="EventUtil.js"></script>
    <script type="text/javascript"> /* 当网络从离线变为在线或者从在线变为离线时,分别触发这两个事件 */ EventUtil.addHandler(window,"online",function(){ alert("Online"); }); EventUtil.addHandler(window,"offline",function(){ alert("Offline"); }); </script>
    </body>
</html>

应用缓存

HTML5 引入了应用程序缓存,这意味着 web 应用可进行缓存,并可在没有因特网连接时进行访问。

应用程序缓存为应用带来三个优势:

  • 离线浏览 - 用户可在应用离线时使用它们
  • 速度 - 已缓存资源加载得更快
  • 减少服务器负载 - 浏览器将只从服务器下载更新过或更改过的资源。

HTML5的应用缓存(application cache),或者简称为appcache,是专门为开发离线Web应用而设计的。Appcache就是从浏览器的缓存中分出来的一块缓存区。要想在这个缓存中保存数据,可以使用一个描述文件(manifest file),列出要下载和缓存的资源。

manifest 文件可分为三个部分:

  • CACHE MANIFEST - 在此标题下列出的文件将在首次下载后进行缓存
  • NETWORK - 在此标题下列出的文件需要与服务器的连接,且不会被缓存
  • FALLBACK - 在此标题下列出的文件规定当页面无法访问时的回退页面(比如 404 页面)

描述文件实例:

CACHE MANIFEST
# 2016-03-10 v1.1.6
./css.css
./big1.jpg
./big2.jpg

NETWORK:
*

第一行,CACHE MANIFEST,是必需的:
CACHE MANIFEST
./css.css
./big1.jpg
./big2.jpg

上面的 manifest 文件列出了三个资源:一个 CSS 文件,两张图片。当 manifest 文件加载后,浏览器会从网站的根目录下载这三个文件。然后,无论用户何时与因特网断开连接,这些资源依然是可用的。

NETWORK

下面的 NETWORK 小节规定文件 “login.php” 永远不会被缓存,且离线时是不可用的:
NETWORK:
login.php

当然可以使用星号来指示所有其他其他资源/文件都需要因特网连接:
NETWORK:
*

FALLBACK

下面的 FALLBACK 小节规定如果无法建立因特网连接,则用 “offline.html” 替代 /html5/ 目录中的所有文件:
FALLBACK:
/html/ /offline.html
注意: 第一个 URI 是资源,第二个是替补。

如需启用应用程序缓存,请在文档的 标签中包含 manifest 属性

<!DOCTYPE HTML>
<html manifest="demo.appcache">
...
</html>

每个指定了 manifest 的页面在用户对其访问时都会被缓存。如果未指定 manifest 属性,则页面不会被缓存(除非在 manifest 文件中直接指定了该页面)。

manifest 文件的建议的文件扩展名是:”.appcache”。

注意:manifest 文件需要配置正确的 MIME-type,即 “text/cache-manifest”。必须在 web服务器上进行配置。

一旦文件被缓存,则浏览器会继续展示已缓存的版本,即使您修改了服务器上的文件。为了确保浏览器更新缓存,您需要更新 manifest 文件。更新注释行中的日期和版本号是一种使浏览器重新缓存文件的办法。

虽然应用程序缓存的意图是确保离线时资源可用,但也有相应的javascriptAPI让你知道它都在做什么。这个API的核心是applicationCache对象,这个对象有一个status属性,属性的值是常量,表示应用缓存的如下当前状态。
status属性:

  • 0:无缓存 即没有与页面相关的应用缓存
  • 1:闲置 即应用缓存未得到更新
  • 2:检查中 即正在下载描述文件并检查更新
  • 3:下载中 即应用缓存正在下载描述文件中指定的资源
  • 4:更新完成,表示应用缓存已经更新了资源,而且所有资源都已经下载完毕,可以通过swapCache()来使用了
  • 5:废弃 即应用缓存的描述文件已经不存在了,因此页面无法再访问应用缓存了
    应用缓存相关事件:表示其状态的改变
  • checking:在浏览器为应用缓存查找更新时触发
  • error:在检查更新或下载资源期间发生错误时触发
  • noupdate:在检查描述文件发现文件无变化时触发
  • downloading:在开始下载应用缓存资源时触发
  • process:在文件下载应用缓存的过程中持续不断地触发
  • updateready事件在页面新的应用缓存下载完毕且可以通过swapCache()使用时触发
  • cached:在应用缓存完整可用时触发

Dmeo

<!DOCTYPE html>
<html lang="en" manifest="demo.appcache" >
    <head>
        <meta charset="utf-8">
        <title>Application Cache</title>
        <link rel="stylesheet" type="text/css" href="css.css">
    </head>
    <body>
    <h1>demo1234</h1>
    <ul>
        <li><img src="big1.jpg"></li>
        <li><img src="big2.jpg"></li>
    </ul>
    <script type="text/javascript" src="EventUtil.js"></script>
    <script type="text/javascript"> window.addEventListener('load',function(e){ //updateready事件在页面新的应用缓存下载完毕且可以通过swapCache()使用时触发 window.applicationCache.addEventListener('updateready',function(e){ console.log(window.applicationCache.status); //applicationCache.status==4表示应用缓存已经更新了资源,而且所有资源都已经下载完毕,可以通过swapCache()来使用了 if(window.applicationCache.status==4){ window.applicationCache.swapCache();//调用swapCache()方法来启用新应用缓存 if(confirm("有新版,你是否要重新载入?")){ window.location.reload(); } }else{ console.log("manifest didn't change") } },false); },false); </script>
    </body>
</html>

数据存储

cookie最初是在客户端用于存储会话消息的。该标准要求服务器对任意HTTP请求发送Set-Cookie HTTP头作为响应的一部分,其中包含会话消息。
cookie的构成

  • 名称:一个唯一确定cookie的名称,必须经过URL编码
  • 值:储存在cookie中的字符串值
  • 域:cookie对于哪个域是有效的。所有向该域发送的请求中都会包含这个cookie信息。
  • 路径:对于指定域中的那个路径,应该向服务器发送cookie
  • 失效时间:表示cookie何时应该被删除的时间戳。默认情况下,浏览器会话结束时即将所有的cookie删除,我们可以自己设置删除时间,因此,cookie可以在浏览器关闭后依然保存在用户的机器上。我们可以通过给cookie设置一个以前的时间来对cookie进行删除
  • 安全标志:指定后,cookie只有在使用SSL连接的时候才发送到服务器

javascript对cookie的基本操作:读取、写入和删除
document.cookie返回当前页面可用的所有cookie的字符串,一系列由分号隔开的名值对儿。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>cookie</title>
    </head>
    <body>
    <script type="text/javascript" src="CookieUtil.js"></script>
    <script type="text/javascript"> //需要通过服务器来进行cookie的设置和访问 //设置cookie CookieUtil.set("name","lisi"); CookieUtil.set("book","javascript"); //读取cookie console.log(CookieUtil.get("name")); console.log(CookieUtil.get("book")); //删除cookie CookieUtil.unset("name"); CookieUtil.unset("book"); //设置cookie,包括它的路径、域、失效时间 CookieUtil.set("name","wangwu",new Date("January 1, 2017"),"www.abc.com/HTML5/cookie","www.abc.com"); //移除上面设置的cookie CookieUtil.unset("name","www.abc.com/HTML5/cookie","www.abc.com"); //设置安全的cookie //指定安全标志后,cookie只有在使用SSL连接的时候才会发送到服务器 //CookieUtil.set("name","lisan",null,null,null,true); </script>
    </body>
</html>

CookieUtil.js

var CookieUtil = {//封装了cookie操作的方法:读取、写入和删除
    get: function (name){//读取单个cookie值
        //根据cookie的名字获取相应的值
        var cookieName = encodeURIComponent(name) + "=",
        //在document.cookie字符串中查找cookie名加上等于号的位置
            cookieStart = document.cookie.indexOf(cookieName),
            cookieValue = null,
            cookieEnd;

//cookie都是有名值对构成的,比如:
//name1=value1;name2=value2;name3=value3
//最后一个名值对后面没有逗号
        if (cookieStart > -1){
//如果找到,那么使用indexOf()查找该位置之后的第一个分号的位置(表示了该cookie的结束位置)
            cookieEnd = document.cookie.indexOf(";", cookieStart);
            if (cookieEnd == -1){
    //-1表示没有找到分号,则表示该cookie是字符串中的最后一个,余下的字符串都是cookie的值
    //document.cookie是获取到当前页面可用的所有cookie字符串,一系列由分号隔开的名值对儿
                cookieEnd = document.cookie.length;
            }
            //substring截取字符串:包含头不包含尾
            cookieValue = decodeURIComponent(document.cookie.substring(cookieStart +
                cookieName.length, cookieEnd));
        }

        return cookieValue;
    },

//写入cookie
    set: function (name, value, expires, path, domain, secure) {
        var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);

        if (expires instanceof Date) {
            cookieText += "; expires=" + expires.toGMTString();
        }
        if (path) {
            cookieText += "; path=" + path;
        }
        if (domain) {
            cookieText += "; domain=" + domain;
        }
        if (secure) {
            cookieText += "; secure";
        }
        document.cookie = cookieText;
    },
//删除cookie
//new Date(0)设置cookie的失效时间
    unset: function (name, path, domain, secure){//删除
        this.set(name, "", new Date(0), path, domain, secure);
    }

};

由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能。cookie信息越大,完成对服务器请求的时间也就越长。尽管浏览器对cookie大小进行了限制,不过最好还是尽可能在cookie中少存储信息,以避免影响性能。

注意:一定不要在cookie中存储重要和敏感的数据。cookie数据并非存储在一个安全环境中,其中包含的任何数据都可以被他人访问。所以不要在cookie中存储像信用卡号或者个人地址之类的数据。

子cookie
为了绕开浏览器的单域名下的cookie数限制,开发人员使用一种称为子cookie(subcookie)的概念子cookie是存放在单个cookie中的更小端的数据。就是使用cookie值来存储多个名值对儿
格式如下:
name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5

子cookie一般也以查询字符串的格式进行格式化
获取子cookie的方法有两个:get()和getAll().
其中get()获取单个子cookie的值,getAll()获取所有子cookie并将它们放入一个对象中返回,对象的属性为子cookie的名称,对应值为子cookie对应的值。get()方法接收两个参数:cookie的名字和子cookie的名字
设置子cookie:set()和setAll()
set()的7个参数:cookie名称、子cookie名称、子cookie值、可选的cookie失效时间或时间的Date对象、可选的cookie路径、可选的cookie域和可选的布尔secure标志所有的可选参数都是作用于cookie本身而非子cookie
setAll的6个参数:cookie名称、包含所有子cookie的对象以及和set()中一样的4个可选参数。
删除子cookie
unset()方法用于删除某个cookie中的单个子cookie而不影响其他的;而unsetAll()方法则等同于CookieUtil.unset(),用于删除整个cookie。和set()以及setAll()一样,路径、域和secure标志必须和之前创建的cookie包含的内容一致。
Dmeo

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>SubCookies Example</title>
    </head>
    <body>
    <script type="text/javascript" src="SubCookieUtil.js"></script>
    <script type="text/javascript"> document.cookie="data=name=lisi&book=javascript"; //取得全部子cookie var data=SubCookieUtil.getAll("data"); console.log(data);//Object {name: "lisi", book: "javascript"} console.log(data.name);//lisi console.log(data.book);//javascript //逐个获取子cookie console.log(SubCookieUtil.get("data","name")); console.log(SubCookieUtil.get("data","book")); </script>
    </body>
</html>
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>SubCookies Example2</title>
    </head>
    <body>
    <script type="text/javascript" src="SubCookieUtil.js"></script>
    <script type="text/javascript"> //设置两个cookie SubCookieUtil.set("data","name","lisi"); SubCookieUtil.set("data","book","javascript"); //删除名字为name的子cookie SubCookieUtil.unset("data","name"); //删除名字为book的子cookie SubCookieUtil.unset("data","book"); //设置全部子cookie和失效时间 SubCookieUtil.setAll("data",{name:"wangwu",book:"java"},new Date("January 1, 2017")); //删除整个cookie SubCookieUtil.unsetAll("data"); </script>
    </body>
</html>

SubCookieUtil.js

/*
var SubCookieUtil = {
    get: function (name, subName){//获取单个相应子cookie
        //subCookies是一个对象
        var subCookies = this.getAll(name);//获取所有的子cookie
        if (subCookies){//如果不为空,返回对应的子cookie
            return subCookies[subName];
        } else {
            return null;
        }
    },

    getAll: function(name){//获取所有的子cookie
//name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5
        var cookieName = encodeURIComponent(name) + "=",
        //查找name=的位置
            cookieStart = document.cookie.indexOf(cookieName),
            cookieValue = null,
            cookieEnd,
            subCookies,
            i,
            parts,
            result = {};//空对象

        if (cookieStart > -1){//如果找到
            cookieEnd = document.cookie.indexOf(";", cookieStart)
            if (cookieEnd == -1){
                cookieEnd = document.cookie.length;
            }
            cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);

            if (cookieValue.length > 0){
                //console.log(cookieValue);//name=lisi&book=javascript
                subCookies = cookieValue.split("&");

                for (i=0, len=subCookies.length; i < len; i++){
                    parts = subCookies[i].split("=");
                    result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
                }

                return result;
            }
        }

        return null;
    },
//设置子cookie
    set: function (name, subName, value, expires, path, domain, secure) {
    /*第一步是获取指定cookie名称对应的所有子cookie。逻辑或操作符"||"用于当getAll()返回null时
    将subcookies设置为一个新对象。
    然后,在subcookies对象上设置好子cookie值并传递给setAll()
    */
        var subcookies = this.getAll(name) || {};
        subcookies[subName] = value;
        this.setAll(name, subcookies, expires, path, domain, secure);

    },
    setAll: function(name, subcookies, expires, path, domain, secure){

        var cookieText = encodeURIComponent(name) + "=",
            subcookieParts = new Array(),
            subName;

        for (subName in subcookies){
            if (subName.length > 0 && subcookies.hasOwnProperty(subName)){
                subcookieParts.push(encodeURIComponent(subName) + "=" + encodeURIComponent(
                    subcookies[subName]));
            }
        }

        if (subcookieParts.length > 0){
            cookieText += subcookieParts.join("&");

            if (expires instanceof Date) {
                cookieText += "; expires=" + expires.toGMTString();
            }

            if (path) {
                cookieText += "; path=" + path;
            }

            if (domain) {
                cookieText += "; domain=" + domain;
            }

            if (secure) {
                cookieText += "; secure";
            }
        } else {
            cookieText += "; expires=" + (new Date(0)).toGMTString();
        }

        document.cookie = cookieText;

    },
    unset: function (name, subName, path, domain, secure){
        var subcookies = this.getAll(name);
        if (subcookies){
            delete subcookies[subName];
            this.setAll(name, subcookies, null, path, domain, secure);
        }
    },

    unsetAll: function(name, path, domain, secure){
        this.setAll(name, null, new Date(0), path, domain, secure);
    }
};

Web Storage

Web Storage的目的是克服由cookie带来的一些限制,当数据需要被严格控制在客户端时,无需持续地将数据发回服务器。

Web Storage的两个主要目的:

  • 提供一种在cookie之外存储会话数据的途径:sessionStorage对象
  • 提供一种存储大量可以跨会话存在的数据的机制:localStorage对象
    这两个对象在支持的浏览器中都是以window对象属性的形式存在的。

Storage类型
Storage类型提供最大的存储空间来存储名值对儿。有如下方法:

  • clear():删除所有值;FF中没有实现
  • getItem(name):根据指定的名字name获取相应的值
  • key(index):获取index位置处的值的名字
  • removeItem(name):删除由name指定的名值对儿
  • setItem(name,value):为指定的name设置一个对应的值

getItem()、removeItem()、setItem()方法可以直接调用,也可以通过Storage对象间接调用。因为每个项目都是作为属性存储在该对象上的,所以可以通过点语法或者方括号语法访问属性来读取值,设置也一样,或者通过delete操作符进行删除。建议使用方法而不是属性来访问数据,以免某个键会意外重写该对象上已经存在的成员。还可以使用length属性来判断有多少名值对儿存放在Storage对象中。

sessionStorage对象

sessionStorage对象存储特定于某个会话的数据,也就是该数据只保持到浏览器关闭。这个对象就像会话cookie,也会在浏览器关闭后消失。存储在sessionStorage中的数据可以跨越页面刷新而存在,同时如果浏览器支持,浏览器崩溃并重启后依然可用。
因为sessionStorage对象绑定于某个服务器会话,所以当文件在本地运行的时候是不可用的。存储在sessionStorage中的数据只能由最初给对象存储数据的页面访问到,所以对多页面应用有限制。
Demo

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Session Storage Example</title>
    </head>
    <body>
    <script type="text/javascript"> //使用属性或者setItem()方法来存储数据 sessionStorage.name="wangwu"; sessionStorage.setItem("book","java"); //当sessionStorage中有数据时,可以使用getItem()或者通过直接访问属性名来获取数据 //使用方法来读取数据 console.log(sessionStorage.getItem("name")); //使用属性来读取数据 console.log(sessionStorage.book); //读取数据,这里采用for-in循环来实现 //这里首先通过key()方法获取指定位置上的名字,然后通过getItem()找出对应该名字的值 for(var key in sessionStorage){ var value=sessionStorage.getItem(key); console.log(key+'='+value); } //要从sessionStorage中删除数据,可以使用delete操作符删除对象属性,也可调用removeItem()方法 delete sessionStorage.name; sessionStorage.removeItem("book"); </script>
    </body>
</html>

localStorage对象

localStorage对象可以持久保存客户端数据。数据保留到通过javascript删除或者是用户清除浏览器缓存。要访问同一个localStorage对象,页面必须来自同一个域名,使用同一种协议,在同一个端口上。
Demo

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Local Storage Example</title>
    </head>
    <body>
    <script type="text/javascript"> //使用方法存储数据 localStorage.setItem("name","haha"); //使用属性存储数据 localStorage.age=23; //使用方法读取数据 console.log(localStorage.getItem("name")); //使用属性读取数据 console.log(localStorage.age); </script>
    </body>
</html>

cookies,sessionStorage 和 localStorage 的区别

  • sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
  • 而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
  • cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。cookie数据始终在同源的http请求中携带(即使不需要),也会在浏览器和服务器间来回传递。sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
  • 存储大小:
    cookie数据大小不能超过4k。
    sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
  • 有效时间:
    localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
    sessionStorage 数据在当前浏览器窗口关闭后自动删除。
    cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭

Web Storage的概念和cookie相似,区别是它是为了更大容量存储设计的。Cookie的大小是受限的,并且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽,另外cookie还需要指定作用域,不可以跨域调用。
除此之外,Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie需要前端开发者自己封装setCookie,getCookie。
但是cookie也是不可以或缺的:cookie的作用是与服务器进行交互,作为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生浏览器的支持除了IE7及以下不支持外,其他标准浏览器都完全支持(ie及FF需在web服务器里运行,值得一提的是IE总是办好事,例如IE7、IE6中的userData其实就是javascript本地存储的解决方案。通过简单的代码封装可以统一到所有的浏览器都支持web storage。localStorage和sessionStorage都具有相同的操作方法,例如setItem、getItem和removeItem等。

1.cookie数据存放在客户的浏览器上,session数据放在服务器上。
2.cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
3.session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
4.单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
5.所以建议:
将登陆信息等重要信息存放为session
其他信息如果需要保留,可以放在cookie中

如何删除一个cookie

1.将时间设为当前时间往前一点。
var date = new Date();
date.setDate(date.getDate() - 1);//真正的删除
setDate()方法用于设置一个月的某一天。
2.expires的设置
document.cookie = ‘user=’+ encodeURIComponent(‘name’) + ‘;expires = ’ + new Date(0)

你可能感兴趣的:(html5,缓存,本地存储)