Cookie 概述

Cookie 概述
Cookie是什么Cookie 是一小段文本信息伴随着用户请求和页面在 Web 服务器和浏览器之间传递。Cookie 包含每次用户访问站点时 Web 应用程序都可以读取的信息。为什么需要Cookie因为HTTP协议是无状态的对于一个浏览器发出的多次请求WEB服务器无法区分 是不是来源于同一个浏览器。所以需要额外的数据用于维护会话。 Cookie 正是这样的一段随HTTP请求一起被传递的额外数据。Cookie能做什么Cookie只是一段文本所以它只能保存字符串。而且浏览器对它有大小限制以及 它会随着每次请求被发送到服务器所以应该保证它不要太大。 Cookie的内容也是明文保存的有些浏览器提供界面修改所以 不适合保存重要的或者涉及隐私的内容。Cookie 的限制。大多数浏览器支持最大为 4096 字节的 Cookie。由于这限制了 Cookie 的大小最好用 Cookie 来存储少量数据或者存储用户 ID 之类的标识符。用户 ID 随后便可用于标识用户以及从数据库或其他数据源中读取用户信息。 浏览器还限制站点可以在用户计算机上存储的 Cookie 的数量。大多数浏览器只允许每个站点存储 20 个 Cookie如果试图存储更多 Cookie则最旧的 Cookie 便会被丢弃。有些浏览器还会对它们将接受的来自所有站点的 Cookie 总数作出绝对限制通常为 300 个。通过前面的内容我们了解到Cookie是用于维持服务端会话状态的通常由服务端写入在后续请求中供服务端读取。 下面本文将按这个过程看看Cookie是如何从服务端写入最后如何传到服务端以及如何读取的。回到顶部Cookie的写、读过程在Asp.net中读写Cookie是通过使用HttpCookie类来完成的它的定义如下public sealed class HttpCookie { // 获取或设置将此 Cookie 与其关联的域。默认值为当前域。 public string Domain { get; set; } // 获取或设置此 Cookie 的过期日期和时间在客户端。 public DateTime Expires { get; set; } // 获取一个值通过该值指示 Cookie 是否具有子键。 public bool HasKeys { get; } // 获取或设置一个值该值指定 Cookie 是否可通过客户端脚本访问。 // 如果 Cookie 具有 HttpOnly 属性且不能通过客户端脚本访问则为 true否则为 false。默认为 false。 public bool HttpOnly { get; set; } // 获取或设置 Cookie 的名称。 public string Name { get; set; } // 获取或设置要与当前 Cookie 一起传输的虚拟路径。默认值为当前请求的路径。 public string Path { get; set; } // 获取或设置一个值该值指示是否使用安全套接字层 (SSL)即仅通过 HTTPS传输 Cookie。 public bool Secure { get; set; } // 获取或设置单个 Cookie 值。默认值为空引用。 public string Value { get; set; } // 获取单个 Cookie 对象所包含的键值对的集合。 public NameValueCollection Values { get; } // 获取 System.Web.HttpCookie.Values 属性的快捷方式。 public string this[string key] { get; set; } }Cookie写入浏览器的过程我们可以使用如下代码在Asp.net项目中写一个Cookie 并发送到客户端的浏览器为了简单我没有设置其它属性。HttpCookie cookie new HttpCookie(MyCookieName, string value); Response.Cookies.Add(cookie);我想很多人都写过类似的代码但是大家有没有想过Cookie最后是如何发送到客户端的呢我们打开Fiddler来看一下吧。从上图您应该能发现我们在服务端写的Cookie最后其实是通过HTTP的响应头这种途径发送到客户端的。每一个写入动作 都会产生一个【Set-Cookie】的响应头。浏览器正是在每次获取请求的响应后检查这些头来接收Cookie的。Asp.net获取Cookie的过程我们可以使用如下代码在Asp.net项目中读取一个CookieHttpCookie cookie Request.Cookies[MyCookieName]; if( cookie ! null ) labCookie1.Text cookie.Value; else labCookie1.Text 未定义;代码同样也很简单还是类似的问题大家有没有想过Cookie是如何传到服务端的呢我们还是继续使用Fiddler来寻找答案吧。从图片中我们可以发现Cookie是放在请求头中发送到服务端的。如果你一直刷新页面就能发现每次HTTP请求Cookie都会被发送。当然了浏览器也不是发送它所接收到的所有Cookie它会检查当前要请求的域名以及目录 只要这二项目与Cookie对应的Domain和Path匹配才会发送。对于Domain则是按照尾部匹配的原则进行的。所以我在访问 www.cnblogs.com 时浏览器并不会将我在浏览 www.163.com 所接收到的 Cookie 发出去。删除Cookie其实就是在写Cookie时设置Expires为一个【早于现在时间的时间】。也就是设置此Cookie已经过期 浏览器接收到这个Cookie时便会删除它们。HttpCookie cookie new HttpCookie(MyCookieName, null); cookie.Expires new DateTime(1900, 1, 1); Response.Cookies.Add(cookie);回到顶部使用Cookie保存复杂对象前面的示例代码大致演示了Cookie的读写操作。不过我们平时可能希望将更复杂的【自定义类型】通过Cookie来保存 那么又该如何操作呢对于这个问题我们定义一个类型来看看如何处理。public class DisplaySettings { public int Style; public int Size; public override string ToString() { return string.Format(Style {0}, Size {1}, this.Style, this.Size); } }上面的代码我定义一个类型用于保存用户在浏览页面时的显示设置。接下来我将介绍二种方法在Cookie中保存并读取它们。方法-1经典做法。注意前面给出的HttpCookie定义代码中的最后二个成员private void WriteCookie_2a() { DisplaySettings setting new DisplaySettings { Style 1, Size 24 }; HttpCookie cookie new HttpCookie(DisplaySettings1); cookie[Style] setting.Style.ToString(); cookie[Size] setting.Size.ToString(); Response.Cookies.Add(cookie); } private void ReadCookie_2a() { HttpCookie cookie Request.Cookies[DisplaySettings1]; if( cookie null ) labDisplaySettings1.Text 未定义; else { DisplaySettings setting new DisplaySettings(); setting.Style cookie[Style].TryToInt(); setting.Size cookie[Size].TryToInt(); labDisplaySettings1.Text setting.ToString(); } }方法-2将对象JSON序列化为字符串。private void WriteCookie_2b() { DisplaySettings setting new DisplaySettings { Style 2, Size 48 }; HttpCookie cookie new HttpCookie(DisplaySettings2, setting.ToJson()); Response.Cookies.Add(cookie); } private void ReadCookie_2b() { HttpCookie cookie Request.Cookies[DisplaySettings2]; if( cookie null ) labDisplaySettings2.Text 未定义; else { DisplaySettings setting cookie.Value.FromJsonDisplaySettings(); labDisplaySettings2.Text setting.ToString(); } }这段代码使用了我定义的二个扩展方法。对于这二种方法我个人更喜欢后者因为它具有更好扩展性如果类型增加了成员不需要修改读写Cookie的代码。不过这种方式产生的有些字符比如【双引号】极少数浏览器(Opera)不支持所以需要做UrlEncode或者Base64编码处理。同理对于第一种方法遇到Value有【双引号】时我们同样需要做UrlEncode或者Base64编码处理。回到顶部Js中读写CookieCookie并非只能在服务端读写在客户端的浏览器中也可以实现对它的读写访问。而且在JS中创建的Cookie对于服务端仍然有效可见 接下来我们来看看在JS中如何写入Cookie演示代码将创建一个按钮并在点击按钮后写入Cookieinput typebutton onclickWriteCookie(); valueWriteCookie / script typetext/javascript function WriteCookie() { var cookie cookie_js22222222; path/; document.cookie cookie; } /script在JS中写Cookie很简单只要给document.cookie赋值一个Cookie字符串即可至于格式可以参考前面用Fiddle看到的结果。再来看一下如何使用JS读取Cookie吧。请参考如下代码input typebutton onclickReadCookie(); valueReadCookie / script typetext/javascript function ReadCookie() { alert(document.cookie); } /script仍然是访问document.cookie不过这次我们得到却是全部的Cookie值每个Key/Value项用分号分开中间则用等号分开。 所以 如果您想在JS中读取Cookie一定要按照这个规则来拆分并解析您要读取的Cookie项。鉴于这样的操作有些繁琐 我们可以jquery.cookie.js插件来轻松完成这个功能有兴趣的朋友也可以看一下它是如何处理的。 这个插件的代码比较少这里就直接贴出注意哦前面我们看到了HttpCookie有个HttpOnly属性如果它为true那么JS是读不到那个Cookie的也就是说 我们如果在服务端生成的Cookie不希望在JS中能被访问可以在写Cookie时设置这个属性。不过通过一些工具还是可以看到它们。接下来我们再来看看Asp.net中Cookie有哪些应用。回到顶部Cookie在Session中的应用在Asp.net中HttpContext, Page对象都有个Session的对象我们可以使用它来方便地在服务端保存一些与会话相关的信息。前面我们也提到过HTTP协议是无状态的对于一个浏览器发出的多次请求WEB服务器无法区分 是不是来源于同一个浏览器。所以为了实现会话服务端需要一个会话标识ID能保存到浏览器让它在后续的请求时都带上这个会话标识ID以便让服务端知道 某个请求属于哪个会话这样便可以维护与会话相关的状态数据。由于Cookie对于用户来说是个不可见的东西而且每次请求都会传递到 服务端所以它就是很理想的会话标识ID的保存容器。在Asp.net中默认也就是使用Cookie来保存这个ID的。注意虽然Asp.net 2.0 也支持无Cookie的会话但那种方式要修改URL也有它的缺点因此这种方法并没有广泛的使用。本文将不对这个话题做过多的分析 就此略过无Cookie会话这种方式。我们来看看Session是如何使用Cookie来保存会话标识ID的在默认的Asp.net配置中Web.config有着如下定义sessionState modeInProc cookieNameASP.NET_SessionId cookielessUseCookies/sessionState如果我们执行以下操作Session[Key1] DateTime.Now;此时我们可以使用一些浏览器提供的工具来查看一下现在的Cookie情况。从图片上看这个Cookie的名字就是我们在配置文件中指出的名称我们可以修改一下配置文件sessionState cookieNameSK/sessionState再来执行上面的写Session的操作然后看Cookie我们可以看到SK的Cookie出现了。说明在截图时我把名称为ASP.NET_SessionId的Cookie删除了。通过上面示例我们可以得到结论Session的实现是与Cookie有关的服务端需要将会话标识ID保存到Cookie中。这里再一次申明除非你使用无Cookie的会话模式否则Session是需要Cookie的支持。反过来Cookie并不需要Session的支持。回到顶部Cookie在身份验证中的应用我想很多人都在Asp.net的开发中使用过Form身份认证。对于一个用户请求 我们可以在服务端很方便地判断它是不是代表一个已登录用户。this.labStatus.Text (Request.IsAuthenticated ? 已登录 : 未登录);那么您有没有好奇过Asp.net是如何识别一个请求是不是一个已登录用户发起的呢说到这里我们就要从用户登录说起了。 为了实现登录及Form认证方式我们需要如下配置authentication modeForms forms nameUserStatus/forms /authentication接下来我们需要实现用户登录逻辑。具体实现方式有很多不过最终的调用都是差不多的如下代码所示private void SetLogin() { System.Web.Security.FormsAuthentication.SetAuthCookie(fish, false); }只要执行了以上代码我们就可以看到前面的判断【Request.IsAuthenticated】返回true最终会显示已登录。 为了探寻这个秘密我们还是来看一下当前页面的Cookie情况。果然多出来一个Cookie名称与我在配置文件中指定的名称相同。我们再来看看如果注销当前登录会是什么样子的private void SetLogout() { System.Web.Security.FormsAuthentication.SignOut(); }