.NET Request.Cookies & Response.Cookies
🏷️ ASP.NET
记录一下最近在调查禁用 .NET 自带的 Session 机制,但是仍然使用 cookie 保存一个类似 SessionId 的值时遇到了以前一直不曾注意的问题。
启用 .NET 默认的 Session 的情况下,并不是第一次请求就会创建 SessionId ,而是在第一次使用
Session
保存数据时才会生成一个 SessionId 保存到客户端的 cookie。调用
Response.Cookies.Clear()
方法并不会清除客户端的 cookie。这是在现在项目中发现的遗留 bug。正确的方法是获取
Request.Cookies
中每个 cookie,设置过期时间为之前的日期之后再新增到Response.Cookies
。示例代码:
csharpvar request = HttpContext.Current.Request; var response = HttpContext.Current.Response; List<string> keys = new List<string>(); for (int i = 0; i < request.Cookies.Keys.Count; i++) { keys.Add(request.Cookies.Keys[i]); } foreach (var key in keys) { HttpCookie httpCookie = request.Cookies[key]; httpCookie.Expires = System.DateTime.Now.AddDays(-1); response.Cookies.Add(httpCookie); }
1
2
3
4
5
6
7
8
9
10
11
12
13通过
Response.Cookies.Add()
方法新增 cookie 到客户端可以参考 HttpResponse.Cookies Property 和 HttpRequest.Cookies Property 中的注解。
ASP.NET 包括两个内部 cookie 集合。通过访问的集合
Cookies
的集合HttpRequest
包含传输中的服务器到客户端的 cookieCookie
标头。通过访问的集合Cookies
的集合HttpResponse
包含在服务器上创建和传输到客户端中的新 cookieSet-Cookie
标头。使用添加 cookie 后
HttpResponse.Cookies
集合,cookie 可立即在HttpRequest.Cookies
集合,即使尚未发送到客户端响应。机翻的中文看起来比较诡异,这里再贴一下原版的英文。
ASP.NET includes two intrinsic cookie collections. The collection accessed through the
Cookies
collection ofHttpRequest
contains cookies transmitted by the client to the server in theCookie
header. The collection accessed through theCookies
collection ofHttpResponse
contains new cookies created on the server and transmitted to the client in theSet-Cookie
header.After you add a cookie by using the
HttpResponse.Cookies
collection, the cookie is immediately available in theHttpRequest.Cookies
collection, even if the response has not been sent to the client.需要注意的是通过
Response.Cookies.Add()
方法新增的 Cookie 会立即自动新增到Request.Cookies
,并且这两个 Cookie 的引用地址是相同的。通过
Response.Cookies.Set()
方法更新 cookie 的值HttpCookieCollection.Set(HttpCookie) Method 中的注解:
Set
方法首先检查 cookie 是否已存在于集合中,如果是这样对其进行更新。Set
方法不允许重复的 cookie 的 cookie 集合中。若要在 cookie 集合中添加重复的 cookie,请使用Add
方法。The
Set
method first checks to see if a cookie already exists in the collection and if so updates it. TheSet
method does not allow duplicate cookies in the cookie collection. To add duplicate cookies in the cookie collection, use theAdd
method.Set
方法不允许出现重复的 cookie(key 相同的 cookie)。根据上面的说法,如果已存在于集合中,则会更新该 cookie,但我测试时貌似并没有更新(待确认)。如果
Response.Cookies
中不存在该 cookie(相同 key),则新增到Response.Cookies
的同时,也会立即自动新增到Request.Cookies
。此时,如果Request.Cookies
中并不存在相同的 cookie,则没有任何问题,规律同上一条一样,Request
和Response
中新增的 cookie 是相同的(地址相同);如果Request.Cookies
中之前已经存在了一条相同的 cookie,则Request.Cookies
会出现两条重复的 key,一个 cookie 的引用地址是和Response.Cookies
中新增的 cookie 是相同的,另一个 cookie 会恢复为最初的值(这个最初的值应该是 HTTP 请求中的 cookie 值)(即使该 cookie 被修改过,甚至已经被从Request.Cookies
删除了)。示例代码如下:
csharp// 获取 Web.config 中的 Session 设置 System.Web.Configuration.SessionStateSection _sessionSetting = ((System.Web.Configuration.SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState")); var requestSessionCookie = context.Request.Cookies.Get(_sessionSetting.CookieName); requestSessionCookie.Value = newSessionId; // 新的 session id requestSessionCookie.Expires = DateTime.Now.Add(_sessionSetting.Timeout); // 新的过期时间 // 此时 Request.Cookies 中的值是会同步修改的,因为 requestSessionCookie 就是从 Request.Cookies 中获取的,指向同一个变量 context.Response.Cookies.Set(requestSessionCookie); // 此时 Request.Cookies 中会出现重复的 key,一个和 Response.Cookies 中的值相同,另一个会恢复为最初的值(这个值应该是 HTTP 请求中的 cookie 值) // 这里如果改成使用 Add 方法,则 Request.Cookies 中仍然会出现两个重复的 key,但是这两个 cookie 的引用地址都是相同的
1
2
3
4
5
6
7
8
9
10
11
12
13这个机制简直匪夷所思!不知道是基于什么理由设计成这样的。暂时也没有找到相关的说明。
Response.Cookies.Get(string name)
通过
HttpContext.Current.Response.Cookies.Get(string name)
方法获取 cookie 时,若 Response 中不存在会自动创建一个 key 为 name 的 cookie,其值为""
,并且会自动同步到HttpContext.Current.Request.Cookies
中。这个特性让我调试时绕了不少弯路,从没想到
Get
方法也会修改Response.Cookies
的值。
另外,Request.Cookies.Get()
方法就没有这个问题。Request.Cookies["sessionid"]
存在多个 key 为 sessionid 的 cookie 时,通过
HttpContext.Current.Request.Cookies["sessionid"]
或者HttpContext.Current.Request.Cookies.Get("sessionid")
获取到的是第一个 key 为 sessionid 的 cookie(按照下标从小到大)。