您的位置:首页 > Web前端 > JavaScript

[转]Cookies揭秘 [Asp.Net, Javascript]

2011-03-01 23:12 316 查看

一,前言

Cookies想必所有人都了解,但是未必所有人都精通。本文讲解了Cookies的各方面知识,并且提出来了最佳实践。这是笔者在日常工作中的积累和沉淀。

二,基础知识

1.什么是Cookies

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

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

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

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

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

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

2.Cookies如何存储

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

IE浏览器的用户可以通过在本地的文档中找到Cookies的txt文件,不同操作系统的位置不同,windowsserver2003/xp都保存在:

C:/DocumentsandSettings/Administrator/Cookies文件夹下。

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

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

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

3.Cookies如何传递

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

(1)请求页面

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

GET/Cookies/Test.aspxHTTP/1.1
Host:localhost:1335
User-Agent:Mozilla/5.0(Windows;U;WindowsNT5.2;zh-CN;rv:1.9.1.1)Gecko/20090715Firefox/3.5.1GTB5(.NETCLR3.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.x200OK
Server:ASP.NETDevelopmentServer/9.0.0.0
Date:Thu,06Aug200903:40:59GMT
X-AspNet-Version:2.0.50727
Set-Cookie:My.Common.TestCookieInfo=Pkid=999&TestValue=aaabbbcccdddeee;expires=Fri,07-Aug-200903:40:59GMT;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:/DocumentsandSettings/Administrator/Cookies/administrator@localhost[1].txt

(2)使用插件

FF下使用WebDeveloper插件可以很方便的查看、删除和修改Cookies:

插件截图:





查看页面Cookies:





三.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集合:

publicsealedclassHttpCookieCollection:NameObjectCollectionBase
{...}


通过HttpResquest和HttpResponse对象的Cookies属性,可以获取和写入当前页面的Cookies。

3.Cookies的内容编码格式

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

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

主要是因为javascript中只能使用UTF编码格式。

4.Cookies的Path属性

Cookies的Path属性表示当前的Cookies可以作用在网站的那个路径下。

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





允许存在两个同名但是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中,如图:





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

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

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

MicrosoftInternetExplorer版本6ServicePack1和更高版本支持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(newHttpCookie("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.6ziqiu.zhangcreated
///</remarks>
///<example>
///假设MyCookiesInfo是从从Cookies中获取对象:
///<code>
///CookieInfoitem=newCookieInfo();//new以后已经从Cookies中构造了对象。
///</code>
///将对象保存在Cookies中:
///<code>
///CookieInfoitem=newCookieInfo();
///item.value="testvalue";
///item.SetCookies("1");//Cookies有效期为1天
///</code>
///</example>
[System.Serializable]
publicclassCookieInfo
{

#region====================ConstructedMethod====================
///<summary>
///构造函数
///</summary>
publicCookieInfo()
{

}
#endregion

#region====================PublicMethod====================
///<summary>
///得到当前Cookies的过期时间
///</summary>
///<returns>过期时间</returns>
publicDateTimeGetExpiresTime()
{
stringcookieName=GetType().ToString();
if(HttpContext.Current.Request.Cookies[cookieName]!=null)
{
returnHttpContext.Current.Request.Cookies[cookieName].Expires;
}
returnDateTime.MinValue;
}

///<summary>
///保存Cookies,过期时间为浏览器关闭则失效。
///</summary>
///<paramname="expiresTime">Cookies过期事件</param>
///<returns>是否保存成功</returns>
publicboolSave()
{
returnthis.Save(DateTime.MinValue);
}

///<summary>
///保存Cookies,需要指定过期时间。
///</summary>
///<paramname="expiresTime">Cookies过期事件</param>
///<returns>是否保存成功</returns>
publicboolSave(DateTimeexpiresTime)
{
stringCookieName=GetType().ToString();
HttpCookieSessionCookie=null;

//对SessionId进行备份.
if(HttpContext.Current.Request.Cookies["ASP.NET_SessionId"]!=null)
{
stringSesssionId=HttpContext.Current.Request.Cookies["ASP.NET_SessionId"].Value.ToString();
SessionCookie=newHttpCookie("ASP.NET_SessionId");
SessionCookie.Value=SesssionId;

}
//设定cookie过期时间.
DateTimedtExpiry=expiresTime;
HttpContext.Current.Response.Cookies[CookieName].Expires=dtExpiry;

//设定cookie域名.
stringdomain=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(PropertyInfopiinPropertys)
{
objectoj=pi.GetValue(this,null);
Typetype=pi.PropertyType;
stringvalueStr=string.Empty;

if(oj!=null&&oj.ToString()!=string.Empty)
{
if(type==Type.GetType("System.DateTime"))
{
valueStr=((DateTime)oj).ToString("yyyy/MM/ddHH: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);
}
}

returntrue;
}

///<summary>
///找回Cookie值
///</summary>
publicvoidLoad()
{
stringcookieValue=string.Empty;
stringCookieName=GetType().ToString();

//通过遍历属性,从cookie中找回值,回写到属性.
PropertyInfo[]Propertys=GetType().GetProperties();

foreach(PropertyInfopiinPropertys)
{
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
{
objectobb=cookieValue;
Typetype=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]
publicclassMyCookieInfo:CookieInfo
{
privateintm_Pkid=0;
publicintPkid
{
get
{
returnm_Pkid;
}
set
{
m_Pkid=value;
}
}

privatestringm_TestValue="";
publicstringTestValue
{
get
{
returnm_TestValue;
}
set
{
m_TestValue=value;
}
}

privateDateTimem_TestDateTime=DateTime.Now;
publicDateTimeTestDateTime
{
get
{
returnm_TestDateTime;
}
set
{
m_TestDateTime=value;
}
}
}


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

保存
Save方法有两个重载,不带参数的Save方法表示Cookies的过期时间与浏览器相同,即浏览器关闭则Cookies消失。否则需要传入Cookies过期时间。


MyCookieInfotestCookies=newMyCookieInfo();
testCookies.Pkid=1;
testCookies.TestValue="中文测试";
testCookies.Save();


读取

MyCookieInfotestCookies=newMyCookieInfo();
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/ddHH:mm:ss",
System.Globalization.DateTimeFormatInfo.InvariantInfo);


现在我们已经可以将一个强类型的对象读取和保存Cookies了。

(3)使用Javascript操作Cookies

在客户端我们同样需要操作Cookies。

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

/article/4677254.html

当然此工具函数稍加修改,就可以变成标准的Javascript函数。

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

工具函数说明:

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

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

方法参数:

名称说明举例
namecookies的主键值读取主键:

$.cookie("singleKey")


写入cookies,值为字符串:

$.cookie("singleKey","","singleKey-value",{expires:1,path:"/",secure:false})

subName子键名称。在写入时请传递空或者null读取子键:

$.cookie("multiKey","subName1")


写入cookies,值为对象:

varsubNameObj={subName1:"aaa",subName2:"bbb",subName3:"ccc"};

$.cookie("multiKey","",subNameObj,{expires:1,path:"/",secure:false});

valueCookies值,可以是字符串或者对象。
如果是对象,则将对象的每个属性保存在Cookies子键。
参见上面实例。
options参数:
expires:可以是数字或者Data类型的对象。
如果传入数字表示几天后过期。
path:路径,默认为域名根目录(“/”)。
secure:是否启用加密,默认为否。

指定过期时间:

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


1天后过期:

vartime=Date();

$.cookie("singleKey","","singleKey-value",{expires:1,path:"/",secure:false})

五.总结

很久没有发表文章了,作为博客园改版后我的第一篇文章,希望对大家的工作能有所帮助。欢迎拍砖!

作者:张子秋
出处:http://www.cnblogs.com/zhangziqiu/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: