Cookies揭秘 [Asp.Net, Javascript]

一,前言

Cookies想必全部人都了解, 可是未必全部人都精通。本文讲解了Cookies的各方面知识, 而且提出来了最佳实践。这是笔者在平常工做中的积累和沉淀。javascript

 

二,基础知识

1.什么是Cookies

Cookie 是一小段文本信息,伴随着用户请求和页面在 Web 服务器和浏览器之间传递。Cookie 包含每次用户访问站点时 Web 应用程序均可以读取的信息。html

例如,若是在用户请求站点中的页面时应用程序发送给该用户的不只仅是一个页面,还有一个包含日期和时间的 Cookie,用户的浏览器在得到页面的同时还得到了该 Cookie,并将它存储在用户硬盘上的某个文件夹中。java

之后,若是该用户再次请求您站点中的页面,当该用户输入 URL 时,浏览器便会在本地硬盘上查找与该 URL 关联的 Cookie。若是该 Cookie 存在,浏览器便将该 Cookie 与页请求一块儿发送到您的站点。而后,应用程序即可以肯定该用户上次访问站点的日期和时间。您可使用这些信息向用户显示一条消息,也能够检查到期日期。jquery

Cookie 与网站关联,而不是与特定的页面关联。所以,不管用户请求站点中的哪个页面,浏览器和服务器都将交换 Cookie 信息。用户访问不一样站点时,各个站点均可能会向用户的浏览器发送一个 Cookie;浏览器会分别存储全部 Cookie。windows

Cookie 帮助网站存储有关访问者的信息。通常来讲,Cookie 是一种保持 Web 应用程序连续性(即执行状态管理)的方法。除短暂的实际交换信息的时间外,浏览器和 Web 服务器间都是断开链接的。对于用户向 Web 服务器发出的每一个请求,Web 服务器都会单独处理。可是在不少状况下,Web 服务器在用户请求页时识别出用户会十分有用。例如,购物站点上的 Web 服务器跟踪每位购物者,这样站点就能够管理购物车和其余的用户特定信息。所以,Cookie 能够做为一种名片,提供相关的标识信息帮助应用程序肯定如何继续执行。浏览器

使用 Cookie 可以达到多种目的,全部这些目的都是为了帮助网站记住用户。例如,一个实施民意测验的站点能够简单地将 Cookie 做为一个 Boolean 值,用它来指示用户的浏览器是否已参与了投票,这样用户便没法进行第二次投票。要求用户登陆的站点则能够经过 Cookie 来记录用户已经登陆,这样用户就没必要每次都输入凭据。服务器

2.Cookies如何存储

Cookies保存在用户的本地机器上,不一样的浏览器存储在不一样的文件夹中,而且按照域名分别保存。即网站之间的Cookies不会彼此覆盖。cookie

IE浏览器的用户能够经过在本地的文档中找到Cookies的txt文件, 不一样操做系统的位置不一样,windows server 2003/xp都保存在:app

C:\Documents and Settings\Administrator\Cookies 文件夹下。asp.net

其中名称txt按照域名保存,好比localhost域下的cookies为:

administrator@localhost[1].txt 或者 administrator@localhost[2].txt

其中后面的[1]和[2]是随着每次保存交替变化的。

3.Cookies如何传递

Cookies的信息是在Web服务器和浏览器之间传递的。保存在Http请求中。

(1)请求页面

在请求一个页面的Http头中,会将属于此页面的本地Cookies信息加在Http头中,注意下面加粗的部分:

GET /Cookies/Test.aspx HTTP/1.1 
Host: localhost:1335 
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.1.1) Gecko/20090715 Firefox/3.5.1 GTB5 (.NET CLR 3.5.30729) 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: zh-cn,zh;q=0.5 
Accept-Encoding: gzip,deflate 
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7 
Keep-Alive: 300 
Connection: keep-alive 
Cookie: My.Common.TestCookieInfo=Pkid=999&TestValue=aaabbbcccdddeee 

(2)页面响应

若是页面要求写入Cookies信息,则返回的Http以下,注意加粗的部分:

HTTP/1.x 200 OK 
Server: ASP.NET Development Server/9.0.0.0 
Date: Thu, 06 Aug 2009 03:40:59 GMT 
X-AspNet-Version: 2.0.50727 
Set-Cookie: My.Common.TestCookieInfo=Pkid=999&TestValue=aaabbbcccdddeee; expires=Fri, 07-Aug-2009 03:40:59 GMT; path=/ 
Cache-Control: private 
Content-Type: text/html; charset=utf-8 
Content-Length: 558 
Connection: Close 

4.Cookies如何查看

(1)查看Cookies的txt文件

IE用户能够直接查看Cookies的txt文件。 
好比:C:\Documents and Settings\Administrator\Cookies\administrator@localhost[1].txt

 

(2)使用插件

FF下使用Web Developer插件能够很方便的查看、删除和修改Cookies:

插件截图:

image 

查看页面Cookies:

image

 

 

 

三. Cookies高级知识

1.Cookie 的限制

大多数浏览器支持最大为 4096 字节的 Cookie。

浏览器还限制站点能够在用户计算机上存储的 Cookie 的数量。大多数浏览器只容许每一个站点存储 20 个 Cookie;注意这里的20个是指主键值,也就是20条Cookies记录,可是每一个Cookies记录还能够包含若干子键,下面会详细解释。若是试图存储更多 Cookie,则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自全部站点的 Cookie 总数做出绝对限制,一般为 300 个。

2.Cookies的存储格式

Cookies能够包含一个主键, 主键再包含子键。好比asp.net中获取Cookies的格式是:

Request.Cookies[key][subkey].ToString();

 

其中的key就是主键,subkey就是主键关联的子键。

(1)本地磁盘存储格式:

My.Common.TestCookieInfo
Pkid=999&TestValue=aaabbbcccdddeee
localhost/
1536
3059603968
30021392
2348960464
30021191
*

其中的Pkid=999&TestValue=aaabbbcccdddeee 是Cookies的值,因为使用了subkey=subvalue的格式, 因此此Cookies是包含子键的。

(2)Javascript中的Cookie格式

在Javascript中给的Cookie是一个字符串,经过document.cookies获取。字符格式以下:

My.Common.SubKey=Pkid=999&TestValue=aaabbbcccdddeee; SingleKey=SingleKeyValue

 

上面的字符串包含了两个Cookies,一个是不包含子键的SingleKey, 一个是包含pkid和TextValue两个子键的My.Common.SubKey,两个Cookie经过“;”分割。

(3)Asp.Net中的Cookies格式

和全部的服务器端语言同样,Asp.Net中使用集合类保存Cookies集合:

public sealed class HttpCookieCollection : NameObjectCollectionBase {...}


经过HttpResquest和HttpResponse对象的Cookies属性,能够获取和写入当前页面的Cookies。

 

3.Cookies的内容编码格式

Cookies的值中能够保存除了“;”之外的标点符号。可是不能保存汉字。保存汉字会出现乱码。

因此对于Cookies中的内容要进行统一的编码和解码。为了在浏览器端和服务器端都可以进行解码和编码, 因此要统一使用UTF编码格式。

主要是由于javascript中只能使用UTF编码格式。

 

4.Cookies的Path属性

Cookies的Path属性表示当前的Cookies能够做用在网站的那个路径下。

好比下面的两个同名的Cookies:

image

容许存在两个同名可是Path不一样的Cookies。

不管是服务器端仍是客户端,在获取时优先获取本页路径下面的Cookies。

也就是说若是在、/chapter10/路径下面的页面, 获取testKey这个Cookies的值,则只能获取到testValue222222这个值。

 

5.Cookies的过时时间

若是保存Cookies时未设置过时时间, 则Cookies的过时时间为“当前浏览器进程有效”,即和Session同样关闭浏览器后则消失。在asp.net中还能够经过设置HttpCookie对象的过时时间为DateTime.MinValue来指定此Cookies为跟随浏览器生效。(这句话来之不易啊,在脑壳等人的帮助下才查到的。)

若是设置了过时时间而且大于当前时间,则会保存Cookies值。

若是设置了过时时间可是小于等于当前时间,则清除Cookies值。

 

6.Cookies与Session

有时咱们会忽略Cookies与Session的关系。可是二者是密不可分的。

Session的惟一标示:SessionID是一般保存在Cookies中的(也能够保存在URL中)。对于Asp.Net而言,SessionID保存在键值为“ASP.NET_SessionId”的Cookies中,如图:

image

由于Cookies的存储数量是有限制的,因此咱们的系统在保存Cookies的时候必定要注意防止冲掉这一个关键的Cookies。在下文介绍的最佳实践-以强对象方式保存Cookies的代码中特地对这个Cookies作了处理。

注意,在客户端使用javascript脚本没法获取“ASP.NET_SessionId”的Cookies, 由于此Cookies在服务器端设置了HttpOnly属性为true。

ASP.Net中HttpCookie对象的HttpOnly 属性 指定一个Cookie 是否可经过客户端脚本访问。不能经过客户端脚本访问为 true;不然为 false。默认值为 false。此属性并不能彻底阻止客户端在本地获取cookies,可是能够增长经过脚本直接获取的难度。

Microsoft Internet Explorer 版本 6 Service Pack 1 和更高版本支持 Cookie 属性 HttpOnly

 

7.Cookies加密

在设置Cookies的属性时,有一个选项Secure用来控制Cookie的加密特性。

若是经过 SSL 链接 (HTTPS) 传输 Cookie,则为 true;不然为 false。默认为 false。

若是咱们保存一个Cookies并设置加密,那么在非HTTPS的页面中,不管是使用javascript仍是服务器端都没法得到此Cookies。可是在本地依然能够看到此Cookies的存在。

 

8.Cookies与Ajax

若是Ajax请求访问一个服务器页面,此服务器页面是能够向用户浏览器写入Cookies和Session的。

 

四. Cookies最佳实践

在了解了Cookies的相关知识后,下面提出最佳的事件方法。其中包括客户端和服务器端两部分。

(1)Asp.Net 中保存Cookies

一般,咱们使用Request和Response对象来直接操做Cookies:

写入Cookies:

Response.Cookies["k1"].Value = "k1Value"; Response.Cookies["k2"]["k2-1"] = "k2-1Value"; Response.Cookies.Add(new HttpCookie("k3", "k3Value"));

 

读取Cookies:

Request["k1"] ;
Request.Cookies["k1"].Value ;
Request.Cookies["k2"]["k2-1"]; Request.Cookies.Get(0).Value;

 

注意Request["k1"]这个你们熟悉的获取get和post参数的方法,同时还可以获取Cookies的值!

另外上面语句中的有些是必须经过Value属性访问的,有些则不须要。

(2)以对象方式保存Cookies

下面提供一个能够以对象方式总体保存Cookies的工具类。而且只占用一条Cookies,全部的属性都存在子键上。

  • 源代码:  
    /// <summary>
    /// Cookies基类。将须要保存Cookies的数据类此类派生,能够将强类型对象在Cookies中的保存和读取。 /// </summary> /// <remarks> /// 2009.8.6 ziqiu.zhang created /// </remarks> /// <example> /// 假设MyCookiesInfo是从 从Cookies中获取对象: /// <code> /// CookieInfo item = new CookieInfo(); //new之后已经从Cookies中构造了对象。 /// </code> /// 将对象保存在Cookies中: /// <code> /// CookieInfo item = new CookieInfo(); /// item.value = "test value"; /// item.SetCookies("1"); //Cookies有效期为1天 /// </code> /// </example> [System.Serializable] public class CookieInfo { #region ==================== Constructed Method ==================== /// <summary> /// 构造函数 /// </summary> public CookieInfo() { } #endregion #region ==================== Public Method ==================== /// <summary> /// 获得当前Cookies的过时时间 /// </summary> /// <returns>过时时间</returns> public DateTime GetExpiresTime() { string cookieName = GetType().ToString(); if (HttpContext.Current.Request.Cookies[cookieName] != null) { return HttpContext.Current.Request.Cookies[cookieName].Expires; } return DateTime.MinValue; } /// <summary> /// 保存Cookies,过时时间为浏览器关闭则失效。 /// </summary> /// <param name="expiresTime">Cookies过时事件</param> /// <returns>是否保存成功</returns> public bool Save() { return this.Save(DateTime.MinValue); } /// <summary> /// 保存Cookies,须要指定过时时间。 /// </summary> /// <param name="expiresTime">Cookies过时事件</param> /// <returns>是否保存成功</returns> public bool Save(DateTime expiresTime) { string CookieName = GetType().ToString(); HttpCookie SessionCookie = null; //对 SessionId 进行备份. if (HttpContext.Current.Request.Cookies["ASP.NET_SessionId"] != null) { string SesssionId = HttpContext.Current.Request.Cookies["ASP.NET_SessionId"].Value.ToString(); SessionCookie = new HttpCookie("ASP.NET_SessionId"); SessionCookie.Value = SesssionId; } //设定cookie 过时时间. DateTime dtExpiry = expiresTime; HttpContext.Current.Response.Cookies[CookieName].Expires = dtExpiry; //设定cookie 域名. string domain = string.Empty; if (HttpContext.Current.Request.Params["HTTP_HOST"] != null) { //domain = "www.elong.com"; domain = HttpContext.Current.Request.Params["HTTP_HOST"].ToString(); } //若是是www.elong.com或多级域名,须要转化为elong.com if (domain.IndexOf(".") > -1) { string[] temp = domain.Split('.'); if (temp.Length >= 3) { domain = temp[temp.Length - 2].Trim() + "." + temp[temp.Length - 1].Trim(); } HttpContext.Current.Response.Cookies[CookieName].Domain = domain; } //把类的属性, 写入Cookie. PropertyInfo[] Propertys = GetType().GetProperties(); foreach (PropertyInfo pi in Propertys) { object oj = pi.GetValue(this, null); Type type = pi.PropertyType; string valueStr = string.Empty; if (oj != null && oj.ToString() != string.Empty) { if (type == Type.GetType("System.DateTime")) { valueStr = ((DateTime)oj).ToString("yyyy/MM/dd HH:mm:ss", System.Globalization.DateTimeFormatInfo.InvariantInfo); } else { valueStr = oj.ToString(); } HttpContext.Current.Response.Cookies[CookieName][pi.Name] = HttpUtility.UrlEncode(valueStr); } } //若是cookie总数超过20 个, 重写ASP.NET_SessionId, 以防Session 丢失. if (HttpContext.Current.Request.Cookies.Count > 20 && SessionCookie != null) { if (SessionCookie.Value != string.Empty) { HttpContext.Current.Response.Cookies.Remove("ASP.NET_SessionId"); HttpContext.Current.Response.Cookies.Add(SessionCookie); } } return true; } /// <summary> /// 找回Cookie值 /// </summary> public void Load() { string cookieValue = string.Empty; string CookieName = GetType().ToString(); //经过遍历属性, 从cookie 中找回值, 回写到属性. PropertyInfo[] Propertys = GetType().GetProperties(); foreach (PropertyInfo pi in Propertys) { try { cookieValue = HttpUtility.UrlDecode(HttpContext.Current.Request.Cookies[CookieName][pi.Name].ToString()); } catch { cookieValue = string.Empty; } if (pi.CanWrite && cookieValue != null && cookieValue != string.Empty) { try { object obb = cookieValue; Type type = pi.PropertyType; obb = Convert.ChangeType(obb, type); pi.SetValue(this, obb, null); } catch { } } } } #endregion }
  • 使用

首先说明如何使用此类。

为想要保存在Cookies中的类创建模型,而且继承自CookieInfo便可。好比下面创建了MyCookieInfo类,其中包含属性pkid,TestValue和TestDateTime:

    /// <summary>
    /// 保存Cookies的数据对象 /// </summary> [System.Serializable] public class MyCookieInfo : CookieInfo { private int m_Pkid = 0; public int Pkid { get { return m_Pkid ; } set { m_Pkid = value ; } } private string m_TestValue = ""; public string TestValue { get { return m_TestValue; } set { m_TestValue = value; } } private DateTime m_TestDateTime = DateTime.Now; public DateTime TestDateTime { get { return m_TestDateTime; } set { m_TestDateTime = value; } } }

 

接下来就可使用对象的Save和Load方法保存和读取Cookies:

  • 保存 
    Save方法有两个重载,不带参数的Save方法表示Cookies的过时时间与浏览器相同,即浏览器关闭则Cookies消失。不然须要传入Cookies过时时间。
    MyCookieInfo testCookies = new MyCookieInfo();
    testCookies.Pkid = 1;
    testCookies.TestValue = "中文测试";
    testCookies.Save(); 
  • 读取 
    MyCookieInfo testCookies = new MyCookieInfo(); testCookies.Load();
    this.lblMsg.Text = "Pkid:" + testCookies.Pkid.ToString(); this.lblMsg.Text += ",TestValue:" + testCookies.TestValue.ToString(); this.lblMsg.Text += ",TestDateTime:" + 
    testCookies.TestDateTime.ToString("yyyy/MM/dd HH:mm:ss",
    System.Globalization.DateTimeFormatInfo.InvariantInfo);

如今咱们已经能够将一个强类型的对象读取和保存Cookies了。

 

 

(3)使用Javascript操做Cookies

在客户端咱们一样须要操做Cookies。

下面是封装了的专门用于操做Cookies的jQuery工具函数。若是还有人不知道jQuery是什么,请参考个人“从零开始学习jQuery”系列教程:

http://www.cnblogs.com/zhangziqiu/archive/2009/04/30/jQuery-Learn-1.html

固然此工具函数稍加修改,就能够变成标准的Javascript函数。

下载地址:http://files.cnblogs.com/zhangziqiu/jquery.extend-lastest.js

工具函数说明:

方法签名: jQuery.cookie(name, subName, value,  options)

方法说明:读取、写入、删除Cookies

方法参数:

名称 说明 举例
name cookies的主键值 读取主键: 
$.cookie("singleKey")


写入cookies,值为字符串: 
$.cookie("singleKey", "", "singleKey-value", { expires: 1, path: "/", secure: false })
subName 子键名称。在写入时请传递空或者null 读取子键: 
$.cookie("multiKey", "subName1")


写入cookies,值为对象: 
var subNameObj = { subName1: "aaa", subName2: "bbb", subName3: "ccc" };
$.cookie("multiKey", "", subNameObj, { expires: 1, path: "/", secure: false });
value Cookies值,能够是字符串或者对象。 
若是是对象,则将对象的每一个属性保存在Cookies子键。
参见上面实例。
options 参数: 
expires:能够是数字或者Data类型的对象。 
若是传入数字表示几天后过时。
path:路径,默认为域名根目录(“/”)。 
secure:是否启用加密,默认为否。 



指定过时时间:

var myDate = new Date(); myDate.setFullYear(2009, 10, 10); $.cookie("singleKey", "", "singleKey-value", { expires: myDate, secure: false })
 

1天后过时:

var time = Date();
$.cookie("singleKey", "", "singleKey-value", { expires: 1, path: "/", secure: false })

 

五.总结

好久没有发表文章了,做为博客园改版后个人第一篇文章, 但愿对你们的工做能有所帮助。 欢迎拍砖!

相关文章
相关标签/搜索