当前位置: 首页 > 科技观察

客户端数据存储----Cookie来自《高程3》

时间:2023-03-21 15:14:41 科技观察

前言本文主要介绍Cookie技术的阅读总结,不过我觉得逻辑上会和WebStorage技术进行比较,所以稍后再总结,敬请期待姐姐WEB存储总结。首先先来个总结:Cookies用于本地数据存储,在服务器与浏览器交互中出现在响应Set-Cookie头和请求Cookie头中。它们受限于单个域名下cookie的数量、单个cookie的大小、性能和安全性。子cookie技术的出现,缓解了单个域名下cookie数量的限制,并且有一整套子cookie可用的工具功能。HTTPCookie简介用户的信息是绝对存储在客户端的,这就对客户端数据存储提出了要求。最早的解决方案是Cookie。HTTPCookie,通常直接称为cookie,最初用于在客户端存储会话信息。该标准要求服务器发送一个Set-CookieHTTP标头作为对任何HTTP请求的响应的一部分,其中包含会话信息。一个典型的响应头:HTTP/1.1200OKContent-type:text/htmlSet-Cookie:name=valueOther-header:other-header-value这个HTTP响应设置了一个cookie,name为name,value为value,name和Values必须传递时进行URL编码。浏览器是这样存储session信息的,之后通过给每个请求添加一个Cookie头,将信息发回给服务器:GET/index.htmlHTTP/1.1Cookie:name=valueOther-header:other-header-valueCookieaccess,数量和大小限制Cookie本质上与特定域名绑定。设置cookie后,当向创建它的域名发送请求时将包含该cookie。此限制可确保存储在cookie中的信息仅可供批准的收件人访问,而其他域则无法访问。由于cookie是保存在客户端电脑上的,所以添加了一些限制,以保证cookie不会被恶意使用,也不会占用过多的磁盘空间。每个域的cookie总数是有限的,但这因浏览器而异:1)IE6及以下版本限制每个域最多20个cookie。2)IE7及以后版本最多可以有50个域名。IE7最初支持每个域名最多20个cookie,后来通过微软的补丁进行了更新。3)Firefox限制每个域最多50个cookie。4)Opera限制每个域最多30个cookie。5)Safari和Chrome对每个域的cookie数量没有硬性限制。当cookie设置超过单个域名的限制后,浏览器会清除之前设置的cookie。IE和Opera删除最近最少使用(LRU,LeastRecentlyUsed)cookie,为新设置的cookie腾出空间。Firefox似乎随机决定清除哪个cookie,因此考虑cookie限制以避免意外后果很重要。浏览器中的cookie大小也有限制。大多数浏览器的长度限制约为4096B(正负1)。为了获得最佳的浏览器兼容性,***将整个cookie长度限制为4095B(包括4095)。大小限制影响一个域下的所有cookie,而不是单独的每个cookie。如果您尝试创建超过最大大小限制的cookie,该cookie将被静默丢弃。cookie的组成1)名称:唯一标识cookie的名称。Cookie名称不区分大小写。cookie名称必须经过URL编码。2)Value:存储在cookie中的字符串值。值必须经过URL编码。3)域:cookie对哪个域有效。对该域的所有请求都将包含此cookie信息。4)路径:对于指定域中的那个路径,应该向服务器发送一个cookie。5)Expirationtime:一个时间戳,指示cookie应该被删除的时间(即应该停止向服务器发送cookie的时间)。默认情况下,所有cookie在浏览器会话结束时都会被删除;但是,您也可以自己设置删除时间。此值是GMT格式的日期(Wdy、DD-Mon-YYYYHH:MM:SSGMT),指定应删除cookie的确切时间。因此,cookie可以在浏览器关闭后保留在用户的机器上。如果您设置过期日期,cookie将立即被删除。6)安全标志:指定后,只有在使用SSL连接时才会向服务器发送cookie。例如cookie信息只能发送到https://www.wrox.com,但是请求http://www.wrox.com是不能发送cookie的。每条信息都包含在Set-Cookie标头中,由分号和空格分隔。安全标志是cookie中唯一直接包含单词安全的非名称值部分。特别要注意的是,域、路径、过期时间和安全标志都是服务器向浏览器发出的指令(服务器发回的响应),用于指定何时发送cookie。这些参数不会作为cookie信息的一部分发送到服务器,只会将名称-值对发送到服务器。设置cookie的格式如下,与Set-Cookie头中使用的格式相同,如下:name=value;过期=过期时间;路径=域路径;域=域名称;secure用于创建、删除和访问cookie的实用函数是用JavaScript读写的Cookie不是很直观,经常需要编写一些函数来简化cookie的功能。Cookie有三种基本操作:读取、写入和删除。创建cookie的工具函数:varCookieUtil={get:function(name){varcookieName=encodeURIComponent(name)+'=',cookieStart=document.cookie.indexOf(cookieName),cookieValue=null;if(cookieStart>-1){varcookieEnd=document.cookie.indexOf(';',cookieStart);if(cookieEnd==-1){cookieEnd=document.cookie.length;}cookieValue=decodeURIComponent(document.cookie.substring(cookieStart+cookieName.length,cookieEnd));}returncookieValue;},set:function(name,value,expires,path,domain,secure){varcookieText=encodeURIComponent(name)+'='+encodeURIComponent(value);if(expiresinstanceofDate){cookieText+=';expires='+expires.toGMTString();}if(path){cookieText+=';path='+path;}if(domain){cookieText+=';domain='+domain;}if(secure){//secure这里是booleancookieText+=';secure';}document.cookie=cookieText;},unset:function(name,path,domain,secure){this.set(name,'',newDate(0),path,domain,secure);}};CookieUtil.get()方法根据cookie的名称获取对应的值。它在document.cookie字符串中查找cookie名称加上等号。如果找到,请使用indexOf()查找该位置之后的第一个分号(指示cookie结束的位置)。如果没有找到分号,则说明cookie是字符串中的最后一个,字符串的其余部分就是cookie的值。该值使用decodeURIComponent()解码并最终返回。如果未找到cookie,则返回null。CookieUtil.set()方法在页面上设置一个cookie,接收以下参数:cookie的名称、cookie的值、指定何时应删除cookie的可选Date对象,以及可选的URL路径cookie,一个可选的域,以及一个可选的布尔值,指示是否添加安全标志。参数按使用频率排序,只需要前两个。在此方法中,名称和值均使用encodeURIComponent()进行URL编码,并检查其他选项。如果expires参数是Date对象,则Date对象将使用Date对象的toGMTString()方法正确格式化并添加到expires选项。该方法的其余部分是构造cookie字符串并将其设置到document.cookie中。没有直接的方法可以删除现有的cookie。因此,您需要使用相同的路径、域和安全选项再次设置cookie,并将过期时间设置为过去的某个时间。CookieUtil.unset()方法可以处理这种事情。它接收4个参数:要删除的cookie的名称、一个可选的路径参数、一个可选的域参数和一个可选的安全参数。这些参数以空字符串和1970年1月1日的到期时间(Date对象的值初始化为0ms)传递给CookieUtil.set()。这可确保删除cookie。FireBug测试结果表明FireBug对应的是哪个页面,设置的cookie存储在该页面对应的域中。打开本地apache服务器的/localhost/alien/页面,在里面打开firebug。测试示例1:CookieUtil.set("name","Nicholas");CookieUtil.set("book","ProfessionalJavaScript");//读取cookie值console.log(CookieUtil.get("name"));//"Nicholas"console.log(CookieUtil.get("book"));//"ProfessionalJavaScript"测试实例2删除cookie:CookieUtil.unset("name");CookieUtil.unset("book");这时FireBug不显示任何cookie。测试例3打开本地服务器localhost的主页,设置一个securecookie。CookieUtil.set("name","Nicholas",null,null,null,true);console.log(CookieUtil.get("name"));当secure设置为true时,缺少的参数全部定义为null。这是因为JavaScript是按顺序对应参数的。测试结果:安全项显示“安全”。Sub-CookiesSub-Cookies的目的是突破单个域名下Cookies的数量限制,即在一个Cookies中存储多个名称-值对。常见的格式如下:name=name1=value1&name2=value2&name3=value3&name4=value4&name5=value5关于Sub-Cookies设置、获取、删除的实用函数如下:varSubCookieUtil={get:function(name,subName){varsubCookies=this.getAll(name);if(subCookies){returnsubCookies[subName];}else{returnnull;}},getAll:function(name){varcookieName=encodeURIComponent(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){subCookies=cookieValue.split('&');for(i=0,len=subCookies.length;i0&&subcookies.hasOwnProperty(subName)){subcookieParts.push(encodeURIComponent(subName)+'='+encodeURIComponent(subcookies[subName]));}}if(subcookieParts.length>0){cookieText+=subcookieParts.join('&');if(expiresinstanceofDate){cookieText+=';expires='+expires.toGMTString();}if(path){cookieText+=';path='+path;}if(domain){cookieText+=';domain='+domain;}if(secure){cookieText+=';secure';}}else{cookieText+=';expires='+(newDate(0)).toGMTString();}document.cookie=cookieText;},unset:function(name,subName,path,domain,secure){varsubcookies=this.getAll(name);if(subcookies){deletesubcookies[子名];this.setAll(name,subcookies,null,path,domain,secure);}},unsetAll:function(name,path,domain,secure){this.setAll(name,null,newDate(0),path,domain,安全的);}};下面是对上述方法的分析:获取子cookie的方法有两种:get()和getAll(),其中get()获取单个子cookie的值,getAll()获取所有子cookiecookies,放入一个对象返回,对象的属性就是子cookie的名称,对应的值就是子cookie对应的值。get()方法接收两个参数:cookie的名称和子cookie的名称。它所做的是调用getAll()以获取所有子cookie,并仅返回所需的那个(如果cookie不存在,则返回null)。SubCookieUtil.getAll()方法在解析cookie值的方式上与CookieUtil.get()非常相似。不同的是cookie的值不是立即解码,而是先根据&字符划分子cookie放在数组中,然后再根据等号划分每个子??cookie,这样parts数组中的第一部分是子cookie名称。后一部分是子cookie的值。这两项都必须使用decodeURIComponent()进行解码,然后放入结果对象中,***作为方法的返回值。如果cookie不存在,则返回null。set()方法接收7个参数:cookie名称、子cookie名称、子cookie值、可选的cookie过期日期或时间的Date对象、可选的cookie路径、可选的cookie域和可选的布尔安全标志。所有可选参数都适用于cookie本身而不是子cookie。为了在同一个cookie中存储多个子cookie,path、domain、secureflag必须保持一致;可以在写入任何单个子cookie的同时设置整个cookie的到期日期。在该方法中,第一步是获取指定cookie名称对应的所有子cookie。逻辑或运算符“||”用于在getAll()返回null时将子cookie设置为新对象。然后,在subcookies对象上设置subcookie值并将其传递给setAll()。setAll()方法接收6个参数:cookie名称、包含所有子cookie的对象以及与set()中相同的4个可选参数。此方法使用for-in循环迭代第二个参数中的属性。为了保证数据确实被保存,使用了hasOwnProperty()方法保证只有实例属性被序列化到子cookie中。由于可能存在属性名称为空字符串的情况,因此在将其添加到结果对象之前检查属性名称的长度。将每个子cookie的名称-值对存储在subcookieParts数组中,以便稍后使用join()方法将它们与&符号组合。可以通过将过期时间设置为过去的时间来删除常规cookie,但不能删除子cookie。为了删除一个子cookie,必须先获取某个cookie包含的所有子cookie,然后只删除需要删除的子cookie,然后将其余子cookie的值保存为cookie的值。unset()方法用于删除一个cookie中的单个子cookie而不影响其他;而unsetAll()方法相当于CookieUtil.unset(),用于删除整个cookie。与set()和setAll()一样,路径、域和安全标志必须与先前创建的cookie中包含的相匹配。Firebug测试示例//设置两个cookieSubCookieUtil.set("data","name","Nicholas");SubCookieUtil.set("data","book","ProfessionalJavaScript");//设置所有子cookie并使Date失效SubCookieUtil.setAll("data",{name:"Nicholas",book:"ProfessionalJavaScript"},newDate("January1,2018"));//修改name的值,修改cookie的有效期SubCookieUtil.set("data","name","Michael",newDate("February1,2010"));//删除所有子CookiesSubCookieUtil.unsetAll('data');Cookie限制1)单个域名下的数量限制和大小限制:子cookie只是突破了单个域名下cookie的数量限制,但是cookie的大小还是有限制的,所以需要注意子cookie的大小不能使单个cookie超过大小限制。2)性能限制:由于所有cookie都是作为请求头由浏览器发送的,cookie中存储大量信息会影响特定域的请求性能。cookie信息越大,完成对服务器的请求所需的时间就越长。虽然浏览器限制了cookie的大小,但最好在cookie中存储尽可能少的信息,以免影响性能。3)安全限制:cookie数据没有存储在安全的环境中,任何包含在其中的数据都可以被他人访问。因此,请勿在cookie中存储信用卡号或个人地址等数据。cookie的性质及其局限性使其不太适合存储大量信息,因此出现了其他方法。