C# 细说Cookie

细说Cookie

Cookie虽然是个很简单的东西,但它又是WEB开发中一个很重要的客户端数据来源,而且它可以实现扩展性很好的会话状态,所以我认为每个WEB开发人员都有必要对它有个清晰的认识。本文将对Cookie这个话题做一个全面的描述,也算是我对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项目中读取一个Cookie

HttpCookie 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.FromJson<DisplaySettings>();
        labDisplaySettings2.Text = setting.ToString();
    }
}

这段代码使用了我定义的二个扩展方法。『点击此处展开』

/// <summary>
/// 将一个对象序列化成 JSON 格式字符串
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public static string ToJson(this object obj)
{
    if( obj == null )
        return string.Empty;

    JavaScriptSerializer jss = new JavaScriptSerializer();
    return jss.Serialize(obj);
}

/// <summary>
/// 从JSON字符串中反序列化对象
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cookie"></param>
/// <returns></returns>
public static T FromJson<T>(this string cookie)
{
    if( string.IsNullOrEmpty(cookie) )
        return default(T);

    JavaScriptSerializer jss = new JavaScriptSerializer();
    return jss.Deserialize<T>(cookie);
}

对于这二种方法,我个人更喜欢后者,因为它具有更好扩展性:如果类型增加了成员,不需要修改读写Cookie的代码。
不过,这种方式产生的有些字符,比如【双引号】,极少数浏览器(Opera)不支持,所以需要做UrlEncode或者Base64编码处理。
同理,对于第一种方法,遇到Value有【双引号】时,我们同样需要做UrlEncode或者Base64编码处理。

Js中读写Cookie

Cookie并非只能在服务端读写,在客户端的浏览器中也可以实现对它的读写访问。而且在JS中创建的Cookie对于服务端仍然有效(可见),接下来我们来看看在JS中如何写入Cookie,演示代码将创建一个按钮,并在点击按钮后写入Cookie

<input type="button" onclick="WriteCookie();" value="WriteCookie" />

<script type="text/javascript">
    function WriteCookie() {
        var cookie = "cookie_js=22222222; path=/";
        document.cookie = cookie;
    }    
</script>

在JS中写Cookie很简单,只要给document.cookie赋值一个Cookie字符串即可,至于格式,可以参考前面用Fiddle看到的结果。

再来看一下如何使用JS读取Cookie吧。请参考如下代码:

<input type="button" onclick="ReadCookie();" value="ReadCookie" />

<script type="text/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 mode="InProc" cookieName="ASP.NET_SessionId" cookieless="UseCookies"></sessionState>

如果我们执行以下操作:

Session["Key1"] = DateTime.Now;

此时,我们可以使用一些浏览器提供的工具来查看一下现在的Cookie情况。

从图片上看,这个Cookie的名字就是我们在配置文件中指出的名称,我们可以修改一下配置文件:

<sessionState cookieName="SK"></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 mode="Forms" >
    <forms name="UserStatus"></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();
}

看到了吗,名为"UserStatus"的Cookie不见了。此时如果你再去观察【Request.IsAuthenticated】,可以发现它此时返回 false。或者,您也可以再试一次,登录后,直接删除名为"UserStatus"的Cookie,也能发现登录状态将显示"未登录"。或许,您还是有点不清楚前面我调用【System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);】后,Asp.net做了些什么,回答这个问题其实很简单:自己用Reflector.exe去看一下Asp.net的实现吧。
这里为了更让您能信服登录与Cookie有关,我将直接创建一个Cookie看一下 Asp.net能不能认可我创建的Cookie,并认为登录有效。请看代码:

private void SetLogin()
{
    //System.Web.Security.FormsAuthentication.SetAuthCookie("fish", false);

    // 下面的代码和上面的代码在作用上是等效的。
    FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
        2, "fish", DateTime.Now, DateTime.Now.AddDays(30d), false, string.Empty);
    string str = FormsAuthentication.Encrypt(ticket);

    HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, str);
    Response.Cookies.Add(cookie);
}

如果执行这段代码,您将发现:【Request.IsAuthenticated】返回true,登录状态会显示"已登录"。
至此,我们可以得出一个结论: Form身份认证依赖Cookie,Asp.net就是每次检查我们在配置文件中指定的Cookie名称,并解密这个Cookie来判断当前请求用户的登录状态。

Cookie的安全状况

从以上图片,您应该能发现:浏览器能提供一些界面让用户清楚的观察我们在服务端写的Cookie,甚至有些浏览器还提供很方便的修改功能。如下图所示:

所以,我们在服务端写代码读取Cookie时,尤其是涉及类型转换、反序列化或者解密时,一定要注意这些操作都有可能会失败。而且上图也清楚的反映了一个事实:Cookie中的值都是“一目了然”的,任何人都能看到它们。所以,我们尽量不要直接在Cookie中保存一些重要的或者敏感的内容。如果我们确实需要使用Cookie保存一些重要的内容,但又不希望被他人看懂,我们可以使用一些加密的方法来保护这些内容。

1. 对于一些重要性不高的内容,我们可以使用Base64之类的简单处理方式来处理。

2. 对于重要性相对高一点的内容,我们可以利用.net提供的一些加密工具类,自己来设计加密方法来保护。不过,密码学与加密解密并不是很简单的算法,因此,自己设计的加密方式可能不会很安全。

3. 重要的内容,我们可以使用.net提供的FormsAuthenticationTicket,FormsAuthentication来加密。我认为这种方式还是比较安全的。毕竟前面我们也看过了,Asp.net的Form身份认证就是使用这种方式来加密用户登录的身份标识的,所以,如果这种方式不安全,也就意味着Asp.net的身份认证也不安全了。如果您使用这种方式来加密,那么请注意:它产生的加密后文本还是比较大的,前面我也提到过,每次请求时,浏览器都会带上与请求相匹配的所有Cookie,因此,这种Cookie会对传输性能产生一定的影响,所以,请小心使用,切记不可过多的使用。

这里要补充一下:去年曾经出现过【Padding Oracle Attack】这个话题,一些人甚至错误的认为是Asp.net加密方式不安全!如果您也是这样认为的,那么可以看一下这篇文章: 浅谈这次ASP.NET的Padding Oracle Attack相关内容 ,以消除这个错误的认识。当然了,我们也可以从这个话题得到一些收获:解密失败时,不要给出过多的提示,就当没有这个Cookie存在。

如何在C#发请的请求中使用Cookie

前面我们一直在谈服务端与浏览器中使用Cookie,其实浏览器也是一个普通的应用程序,.net framework也提供一些类也能让我们直接发起HTTP请求,下面我们来看一下如何在C#发请的请求中使用Cookie ,其实也很简单,主要是使用了CookieContainer类,请看以下演示代码:

private static string SendHttpRequestGet(string url, Encoding encoding, 
            CookieContainer cookieContainer)
    {
        if( string.IsNullOrEmpty(url) )
            throw new ArgumentNullException("url");

        if( encoding == null )
            throw new ArgumentNullException("encoding");

        HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
        request.Method = "GET";
        request.CookieContainer = cookieContainer;
        
        using( WebResponse response = request.GetResponse() ) {
            using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {
                return reader.ReadToEnd();
            }
        }
    }

    private void SendHttpDEMO()
    {
        StringBuilder sb = new StringBuilder();
        CookieContainer cookieContainer = new CookieContainer();

        string url = "http://www.taobao.com";
        SendHttpRequestGet(url, Encoding.Default, cookieContainer);

        // 后面可以继续发起HTTP请求,此时将会包含上次从服务器写入的Cookie
        //SendHttpRequestGet("同域名下的其它URL", Encoding.Default, cookieContainer);

        // 至此,我们可以显示取得了哪些Cookie
        CookieCollection cookies = cookieContainer.GetCookies(new Uri(url));
        if( cookies != null ) {
            foreach( System.Net.Cookie cookie in cookies )
                sb.AppendLine(cookie.ToString());
        }
        txtCookies.Text = sb.ToString();
    }

重构与使用总结

在前面的Asp.net示例代码中,我一直使用.net提供的HttpCookie类来操作Cookie,是为了展示用原始的方式来使用Cookie,这些代码有点重复,也有点繁琐,为此,我提供了几个简单的方法可以更容易的使用Cookie,也算是对Cookie使用的一个总结。

/// <summary>
/// 用于方便使用Cookie的扩展工具类
/// </summary>
public static class CookieExtension
{
    // 我们可以为一些使用频率高的类型写专门的【读取】方法

    /// <summary>
    /// 从一个Cookie中读取字符串值。
    /// </summary>
    /// <param name="cookie"></param>
    /// <returns></returns>
    public static string GetString(this HttpCookie cookie)
    {
        if( cookie == null )
            return null;

        return cookie.Value;
    }

    /// <summary>
    /// 从一个Cookie中读取 Int 值。
    /// </summary>
    /// <param name="cookie"></param>
    /// <param name="defaultVal"></param>
    /// <returns></returns>
    public static int ToInt(this HttpCookie cookie, int defaultVal)
    {
        if( cookie == null )
            return defaultVal;

        return cookie.Value.TryToInt(defaultVal);
    }

    /// <summary>
    /// 从一个Cookie中读取值并转成指定的类型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="cookie"></param>
    /// <returns></returns>
    public static T ConverTo<T>(this HttpCookie cookie)
    {
        if( cookie == null )
            return default(T);

        return (T)Convert.ChangeType(cookie.Value, typeof(T));
    }

    /// <summary>
    /// 从一个Cookie中读取【JSON字符串】值并反序列化成一个对象,用于读取复杂对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="cookie"></param>
    /// <returns></returns>
    public static T FromJson<T>(this HttpCookie cookie)
    {
        if( cookie == null )
            return default(T);

        return cookie.Value.FromJson<T>();
    }


    /// <summary>
    /// 将一个对象写入到Cookie
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="name"></param>
    /// <param name="expries"></param>
    public static void WriteCookie(this object obj, string name, DateTime? expries)
    {
        if( obj == null )
            throw new ArgumentNullException("obj");

        if( string.IsNullOrEmpty(name) )
            throw new ArgumentNullException("name");
        

        HttpCookie cookie = new HttpCookie(name, obj.ToString());

        if( expries.HasValue )
            cookie.Expires = expries.Value;

        HttpContext.Current.Response.Cookies.Add(cookie);
    }

    /// <summary>
    /// 删除指定的Cookie
    /// </summary>
    /// <param name="name"></param>
    public static void DeleteCookie(string name)
    {
        if( string.IsNullOrEmpty(name) )
            throw new ArgumentNullException("name");

        HttpCookie cookie = new HttpCookie(name);

        // 删除Cookie,其实就是设置一个【过期的日期】
        cookie.Expires = new DateTime(1900, 1, 1);
        HttpContext.Current.Response.Cookies.Add(cookie);
    }
}

更完整的代码可以从本文的示例代码中获得。(文章底部有下载地址)

使用方式:

public static class TestClass
{
    public static void Write()
    {
        string str = "中国";
        int aa = 25;
        DisplaySettings setting = new DisplaySettings { Style = 3, Size = 50 };
        DateTime dt = new DateTime(2012, 1, 1, 12, 0, 0);

        str.WriteCookie("Key1", DateTime.Now.AddDays(1d));
        aa.WriteCookie("Key2", null);
        setting.ToJson().WriteCookie("Key3", null);
        dt.WriteCookie("Key4", null);
    }

    public static void Read()
    {
        HttpRequest request = HttpContext.Current.Request;

        string str = request.Cookies["Key1"].GetString();
        int num = request.Cookies["Key2"].ToInt(0);
        DisplaySettings setting = request.Cookies["Key3"].FromJson<DisplaySettings>();
        DateTime dt = request.Cookies["Key4"].ConverTo<DateTime>();
    }    
}

注意哦:以上代码中都是直接使用字符串"Key"的形式,这种方式对于大一些的程序在后期可能会影响维护。
所以建议:将访问Cookie所使用的Key能有一个类来统一的定义,或者将读写操作包装成一些属性放在一个类中统一的管理。

public static class CookieValues
{
    // 建议把Cookie相关的参数放在一起,提供 get / set 属性(或者方法)来访问,以避免"key"到处乱写

    public static string AAA
    {
        get { return HttpContext.Current.Request.Cookies["Key1"].GetString(); }
    }
    public static int BBB
    {
        get { return HttpContext.Current.Request.Cookies["Key2"].ToInt(0); }
    }
    public static DisplaySettings CCC
    {
        get { return HttpContext.Current.Request.Cookies["Key3"].FromJson<DisplaySettings>(); }
    }
    public static DateTime DDD
    {
        get { return HttpContext.Current.Request.Cookies["Key4"].ConverTo<DateTime>(); }
    }
}

补充

根据一些朋友提供的反馈,这里再补充4个需要注意的地方:

1. 如果使用Form登录验证且希望使用Cookie方式时,建议设置 cookieless="UseCookies",因为这个参数的默认值是:cookieless="UseDeviceProfile",Asp.net可能会误判。 dudu就吃过亏。

<authentication mode="Forms" >
    <forms name="MyCookieName" cookieless="UseCookies"></forms>
</authentication>

2. Cookie有3个属性,一般我们可以不用设置,但它们的值可以在Web.config中指定默认值:

<httpCookies domain="www.123.com" httpOnlyCookies="true" requireSSL="false"/>

3. 虽然在写Cookie时,我们可以设置name, value之外的其它属性,但是在读取时,是读不到这些设置的。其实在我的示例代码中有体现,我前面也忘记了说明了。

4. HttpRequest.Cookies 与 HttpResponse.Cookies 会有关系(很奇怪吧)。
以下代码演示了这个现象:

protected void Page_Load(object sender, EventArgs e)
{
    DateTime.Now.ToString().WriteCookie("t1", null);

    label1.Text = ShowAllCookies();

    Guid.NewGuid().ToString().WriteCookie("t2", null);

    // 如果去掉下面代码,将会看到2个t1 
    Response.Cookies.Remove("t1");
    Response.Cookies.Remove("t2");
}

private string ShowAllCookies()
{
    StringBuilder sb = new StringBuilder();

    for( int i = 0; i < Request.Cookies.Count; i++ ) {
        HttpCookie cookie = Request.Cookies[i];
        sb.AppendFormat("{0}={1}<br />", cookie.Name, cookie.Value);
    }

    return sb.ToString();
}

上面的试验代码将会一直显示 t1 的Cookie ,这里就不再贴图了。

本文的所有示例代码可以点击此处下载。

#18楼 2011-07-04 00:39 | Ivony...       
删除Cookie正确的方式并非强制过期,因为浏览器只会按照自己的时间来决定Cookie是否过期,这就使得Cookie的删除是可能不成功的。一般而言尽可能使用进程内Cookie(不设置过期时间,关闭浏览器即失效)是一个不错的选择。一定要删除Cookie时,除了设置过期时间外,还应当将Cookie的值设置为一个安全的无效值,当获得这个无效值时,服务器应当当作没有设置Cookie来处理。
  回复  引用  查看    
#19楼 2011-07-04 08:25 | 小宋的幸福       
受教了
  回复  引用  查看    
#20楼 [ 楼主] 2011-07-04 08:27 | fish-li       
@Ivony...
是的,最好同时设置过期时间和值为null
我的示例代码也是这样写的。 :)

  回复  引用  查看    
#21楼 2011-07-04 08:35 | likely       
不错,支持下!
  回复  引用  查看    
#22楼 2011-07-04 08:36 | 轩~雨~阁       
非常感谢。
  回复  引用  查看    
#23楼 2011-07-04 09:00 | jaysh       
牛XX
  回复  引用  查看    
#24楼 2011-07-04 09:22 | 小刚qq       
很不错..支持下...


不知道LZ的代码块用的是什么插件啊..求地址..

  回复  引用  查看    
#25楼 2011-07-04 09:36 | 重构者       
支持
  回复  引用  查看    
#26楼 2011-07-04 09:45 | pepe_Anhwei       

  回复  引用  查看    
#27楼 2011-07-04 09:59 | gooliugle       
mark。
  回复  引用  查看    
#28楼 2011-07-04 10:14 | alangis       
收藏
  回复  引用  查看    
#29楼 2011-07-04 10:43 | 东华一只球       
挺详细,通俗易懂
  回复  引用  查看    
#30楼 2011-07-04 10:59 | Liu liu       
推荐阅读
draft-ietf-httpstate-cookie-13

原理什么的就全明白了
可以去ietf找

很多人,都是水上漂,什么东西都认真负责的,真正精通的人,其实是不多的。

  回复  引用  查看    
#32楼 2011-07-04 11:18 | magicDict       
很久没有看到这么干净和纯粹的文章了。必须支持一个。
  回复  引用  查看    
#33楼 2011-07-04 12:22 | john23.net       
支持下
  回复  引用  查看    
#34楼 2011-07-04 13:19 | ice6       
排版清晰,内容通俗易懂。
  回复  引用  查看    
#35楼 2011-07-04 13:24 | 徐少侠       
支持好文。

关于Cookie尺寸。我见过一个在线背单词的网站,把用户背过的单词的记录都放在Cookie里了。
尺寸比较厉害哦。

好处么则是简化了服务端的一些处理。连数据库都省了。
坏处么就是要用户妥善保管自己的Cookie文件,因此网站专门有地方讲解不同浏览器到哪里去找Cookie文件。

  回复  引用  查看    
#36楼 2011-07-04 13:30 | 高歌       
非常好的教学贴
  回复  引用  查看    
#37楼 2011-07-04 13:47 | XingRoc Sung       
非常漂亮的文章 支持
  回复  引用  查看    
#38楼 2011-07-04 13:55 | kevin0227       
文章不错,收藏啦
  回复  引用  查看    
#39楼 2011-07-04 14:56 | nicetom328       
排版不错,内容更不错
  回复  引用  查看    
#40楼 2011-07-04 15:57 | 悠然自得       
写的很好 很细 学习了
  回复  引用  查看    
#41楼 2011-07-04 17:41 | Kevin Wei       
受教了,还有个疑问,就是为什么方法的参数前面加个this,什么作用啊,前两天看到别人这么写,不明白google了一下,没找到答案,劳博主大驾给小弟弟解释一下! O.O
  回复  引用  查看    
#42楼 [ 楼主] 2011-07-04 19:38 | fish-li       
引用 小刚qq:
很不错..支持下...
不知道LZ的代码块用的是什么插件啊..求地址..

PasteAsVSCode,你自己去google一下吧。
  回复  引用  查看    
#43楼 [ 楼主] 2011-07-04 19:39 | fish-li       
引用 徐少侠:
支持好文。

关于Cookie尺寸。我见过一个在线背单词的网站,把用户背过的单词的记录都放在Cookie里了。
尺寸比较厉害哦。

好处么则是简化了服务端的一些处理。连数据库都省了。
坏处么就是要用户妥善保管自己的Cookie文件,因此网站专门有地方讲解不同浏览器到哪里去找Cookie文件。

哈哈,这个设计太有才了。
  回复  引用  查看    
#44楼 [ 楼主] 2011-07-04 19:41 | fish-li       
引用 Kevin Wei:受教了,还有个疑问,就是为什么方法的参数前面加个this,什么作用啊,前两天看到别人这么写,不明白google了一下,没找到答案,劳博主大驾给小弟弟解释一下! O.O

那就是扩展方法了。C# 3.0 的语法。

你仔细地看一下我上面的示例代码:setting.ToJson()
DisplaySettings类并没有定义ToJson()这个方法,之所以能这样写,是因为我定义了这个扩展方法。
  回复  引用  查看    
#45楼 [ 楼主] 2011-07-04 19:46 | fish-li       
感谢上面各位支持我的朋友,谢了。
  回复  引用  查看    
#46楼 2011-07-04 20:01 | 梦想天空(山边小溪)       
好文啊,顶一下!
  回复  引用  查看    
#47楼 2011-07-04 22:49 | Blink_Star       
很好。。。支持
  回复  引用  查看    
#48楼 2011-07-04 22:52 | KissFly       
很喜欢这种排版,看了很舒服。
  回复  引用  查看    
#49楼 2011-07-04 22:54 | SeaSunK       
另:如果用Jquery的AJAX方式呢。。。楼主。。可以说下吗?

我不知道是不是真的那么巧。。我今天真的死在COOKIE下;
在MVC下,我竟然在control里一定能拿回cookie,但在aspx页里并不一定能拿到。。而且是某些用户。。到现在还不知道什么原因!!!

  回复  引用  查看    
#50楼 [ 楼主] 2011-07-04 23:23 | fish-li       
@SeaSunK
这与MVC,AJAX,JQUERY之类的技术无关,你是不是设置了cookie的path属性呢?建议使用fiddler看一下,我在文章中已经说清楚了。

  回复  引用  查看    
#51楼 2011-07-05 09:51 | 卡恩和巴拉克粉丝       
排版不错,讲得很详细
  回复  引用  查看    
#52楼 2011-07-05 11:40 | Elvin Chen       
坦白说看到标题的时候没有预期能看到这么详细的文章,支持
  回复  引用  查看    
#53楼 2011-07-05 16:51 | Kevin Wei       
引用 Elvin Chen:坦白说看到标题的时候没有预期能看到这么详细的文章,支持

哈哈,楼主都说是细说了!
写的真棒,忍不住再赞一回!
另外问一下,asp.net 是不是请求一次就重新分配一个session id呢?
我下午试了一下,新窗口、新浏览器、刷新 都会重新分配一个session id,我十分不解啊,干嘛要每次重新弄一个?
  回复  引用  查看    
#54楼 2011-07-05 18:08 | SeaSunK       
引用 fish-li:
@SeaSunK
这与MVC,AJAX,JQUERY之类的技术无关,你是不是设置了cookie的path属性呢?建议使用fiddler看一下,我在文章中已经说清楚了。

也就是就算是xmlhttp這鍾對象去請求也會帶head裡的信息咯~~
path倒沒設~~~問題繼續研究中。。。我甚至懷疑跟IIS的配置有關了;
因為我有三個站點(一樣的website),但只有一個是正常;
  回复  引用  查看    
#55楼 2011-07-05 21:01 | 德威。。。       
不错啊。支持一下。
  回复  引用  查看    
#56楼 [ 楼主] 2011-07-05 22:23 | fish-li       
引用 Kevin Wei:
引用Elvin Chen:坦白说看到标题的时候没有预期能看到这么详细的文章,支持

哈哈,楼主都说是细说了!
写的真棒,忍不住再赞一回!
另外问一下,asp.net 是不是请求一次就重新分配一个session id呢?
我下午试了一下,新窗口、新浏览器、刷新 都会重新分配一个session id,我十分不解啊,干嘛要每次重新弄一个?

是的,简单地说,是SessionStateModule在AcquireRequestState事件中,发现ID不存在,就创建了一个,在后面的ReleaseRequestState事件中,发现没有Session的更新动作,又把它删除了。
如果你在一次请求中,发生了写Session的操作,这个ID就会保留了。
  回复  引用  查看    
#57楼 [ 楼主] 2011-07-05 22:29 | fish-li       
引用 SeaSunK:
引用fish-li:
@SeaSunK
这与MVC,AJAX,JQUERY之类的技术无关,你是不是设置了cookie的path属性呢?建议使用fiddler看一下,我在文章中已经说清楚了。

也就是就算是xmlhttp這鍾對象去請求也會帶head裡的信息咯~~
path倒沒設~~~問題繼續研究中。。。我甚至懷疑跟IIS的配置有關了;
因為我有三個站點(一樣的website),但只有一個是正常;

读不到Cookie,只有3个原因:
1.前面没有写入操作。2.Cookie已过期,被浏览器删除了。3.在浏览器发起请求时,Cookie与要请求的Domain,Path不匹配。
具体是哪种原因,可以用fiddler去看一下嘛,看你在写入时的Cookie参数。
你这种情况,我怀疑和domain有关。而且这种问题用fiddler应该也是容易排查的。
  回复  引用  查看    
#58楼 [ 楼主] 2011-07-05 22:30 | fish-li       
还有一点,我在文章中忘记了说明了。这里补充一下:Cookie有3个属性,一般我们可以不用设置,但它们的值可以在Web.config中指定默认值,如下代码所示:
<httpCookies domain="www.123.com" httpOnlyCookies="true" requireSSL="false"/>

  回复  引用  查看    
#59楼 2011-07-06 00:13 | Kevin Wei       
引用 fish-li:
引用Kevin Wei:
引用Elvin Chen:坦白说看到标题的时候没有预期能看到这么详细的文章,支持

哈哈,楼主都说是细说了!
写的真棒,忍不住再赞一回!
另外问一下,asp.net 是不是请求一次就重新分配一个session id呢?
我下午试了一下,新窗口、新浏览器、刷新 都会重新分配一个session id,我十分不解啊,干嘛要每次重新弄一个?

是的,简单地说,是SessionStateModule在AcquireRequestState事件中,发现ID不存在,就创建了一个,在后面的ReleaseRequestS...


您了解的的确很透彻啊,下午由于这个问题没能解决,我回来在技术群里问了一下,一位大哥给我一段msdn上的文字,顿时茅塞顿开!如下
from MSDN:
When using cookie-based session state, ASP.NET does not allocate storage for session data until the Session object is used. As a result, a new session ID is generated for each page request until the session object is accessed. If your application requires a static session ID for the entire session, you can either implement the Session_Start method in the application’s Global.asax file and store data in the Session object to fix the session ID, or you can use code in another part of your application to explicitly store data in the Session object.


  回复  引用  查看    
#60楼 2011-07-06 12:04 | 张自力       
当使用cookie-based会话状态,ASP。 网络不分配存储为会话数据对象的作用是:直到会议。作为一个结果,一个新的会话ID是产生的每一页,直到会议请求对象访问。如果你的应用要求是一个静态的会话ID为整个过程,你可以执行Session_Start法在应用程序的Global.asax文件和数据存储在会话对象来解决这个会话ID,或者你可以用在另一部分代码明确你的应用程序和数据存储在会话对象。
  回复  引用  查看    
#61楼 [ 楼主] 2011-07-06 12:38 | fish-li       
@Kevin Wei
哈哈,过奖了。这些秘密在Asp.net的源代码里有的哦。
不过,建议还是不要使用Session . 以后我可能会专门谈一下Session的缺点及替代解决方案。

  回复  引用  查看    
#62楼 2011-07-06 20:49 | Kevin Wei       
@fish-li
恩,虽然是有,但我们没有了解那么深,若您有时间的话,希望能早点看到您对session的优化方案!静候着呢!

  回复  引用  查看    
#63楼 [ 楼主] 2011-07-06 22:41 | fish-li       
@Kevin Wei
好的,请关注我的博客吧。

  回复  引用  查看    
#64楼 2011-07-07 06:09 | LoveJenny       
写的很好
  回复  引用  查看    
#65楼 2011-07-07 16:42 | zhangmeiqing       
值得推荐,写得很仔细!
  回复  引用  查看    
#66楼 2011-07-08 15:54 | SeaSunK       
引用 fish-li:
还有一点,我在文章中忘记了说明了。这里补充一下:Cookie有3个属性,一般我们可以不用设置,但它们的值可以在Web.config中指定默认值,如下代码所示:
<httpCookies domain="www.123.com" httpOnlyCookies="true" requireSSL="false"/>

先很感谢楼主的解答:
我具体说说问题,还望楼主分析一下:
第一点:cookie是肯定写到客户端了;而每次请求都能将之前cookie发到服务器了。这个可以用fiddler或chrome/firebug都很轻松知道;
第二点:时间是关闭当前会话cookie才会掉失;
第三点:domain和path都是默认的,令我也试过设置(domain,在web.config里)
第四点:站点里有几个cookie,但偏偏只有form验证的这个cookie不能读取;
第五点:但我只要改过web.config(就是让web.config变动过,重新保存过,因为改过web.config会触发一些东西重新启动吧),那么第一次是可以获取的,但以后怎么弄都不行了;
第六点:假如登录了(也就是cookie能读了),这时候我在浏览器里打开另一个标签B再次访问站点。。这时候就一定能登录了;但将之前的那个标签窗口关了。。然后再回来刷新这个标签B窗口,cookie还是发送出去了,且没变,但在request里读的时候又不能读到了;
第六点:我已经连machineKey都配好。结果却一样不行;
现在非常急切望楼主解答,非常感谢你。
新进展:
由于我是在本地测试:
所在我在IIS里指定了一个域名是指向本机的(如dev.test.com),端口设为8080;
而我利用VS的内置调试也是dev.test.com,只是端口不同,如1897;
结果是:
VS内置的调试,即端口为1897的就没问题;
但8080端口的还是有问题;由于域名一样,所以他们是共享一个cookie的;
  回复  引用  查看    
#67楼 [ 楼主] 2011-07-09 00:12 | fish-li       
@SeaSunK
如果刚好是FormM验证的Cookie读不到,但看到它却实提交了。
那么表示服务器认为Cookie不是它发出的,或者说,它无法解密它,随后便把它删除了,你当然就认为读不到了。
你将下面的代码放在Global.asax中,
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if( cookie != null && string.IsNullOrEmpty(cookie.Value) == false ) {
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);
}
}
如果你刷新页面,出现了黄页,显然就是Cookie不能解密所致。否则,你肯定就能读到它了(前提是Cookie有提交到服务器,你可以设个断点看一下)。

  回复  引用  查看    
#68楼 2011-07-11 11:28 | SeaSunK       
引用 fish-li:
@SeaSunK
如果刚好是FormM验证的Cookie读不到,但看到它却实提交了。
那么表示服务器认为Cookie不是它发出的,或者说,它无法解密它,随后便把它删除了,你当然就认为读不到了。
你将下面的代码放在Global.asax中,
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpCookie cookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if( cookie != null && str...

好多謝樓主的幫助。。
問題已經得到解決:解決方法請看dudu寫的一篇文章:
http://www.cnblogs.com/dudu/archive/2011/03/06/asp_net_4_browser_cookie.html
但卻帶出另一個疑問:我自從配置了cookieless後。。我再恢復過來,已不能重現之前所說的情況。。即可以登錄了。。所以樓主所給的測試方法都通過了~~~我已不能用現在所擁有的知識去解釋這一切了~~
  回复  引用  查看    
#69楼 [ 楼主] 2011-07-11 20:28 | fish-li       
看样子以后还是设置 cookieless="UseCookies" 会比较保险。
  回复  引用  查看    
#70楼 2011-07-12 14:50 | amityat       
写的比较细致,对以前的知识点又跟着复习了一遍。感谢!
  回复  引用  查看    
#71楼 2011-07-18 13:51 | Eric·liu       
赞一个。希望楼主介绍下跨域时cookie传递方面的内容
  回复  引用  查看    
#72楼 2011-07-18 16:13 | weishao       
发现楼主很注重细节,总结的很好,学习了!
欢迎.net家族的斗士们,踊跃加入,共同探讨微软.net的奥秘,共同维护和推广.net的应用!69594961

  回复  引用  查看    
#73楼 2011-07-19 12:33 | Capt.Liu       
支持,写得非常好
  回复  引用  查看    
#74楼 2011-07-22 11:12 | 七千米深蓝       
收藏了!
  回复  引用  查看    
#75楼 2011-07-22 14:40 | kK_wen       
支持一下
  回复  引用  查看    
#76楼 2011-07-25 15:44 | 肉.肉       
寫的真好,學習!
  回复  引用  查看    
#77楼 2011-08-01 17:16 | chenzhaohf       
学习了 支持一下
  回复  引用  查看    
#78楼 2011-08-03 20:51 | popzhou       
学习了,好文!
  回复  引用  查看    
#79楼 2011-08-09 18:02 | 下个路口       
讲解很详细
  回复  引用  查看    
#80楼 2011-08-11 20:27 | Jesong       
一个域名下最多几个cookie,一个cookie的数据最大是多少?
  回复  引用  查看    
#81楼 [ 楼主] 2011-08-11 21:58 | Fish Li       
@Jesong
这些参数与每个浏览器有关,并没有统一的规定。你可以去google一下。

  回复  引用  查看    
#82楼 2011-08-14 21:35 | Carl78       
学习了。
对Cookie有了比较完整的认识.

  回复  引用  查看    
#83楼 2011-08-15 13:31 | 我是小菜鸟       
是好文章,不过为什么那么长啊~~~~
我一看是长的就没耐性啦,唉,我这人就是急性子,咋办呢。
收藏起来。以备不时只需

  回复  引用  查看    
#84楼 2011-08-18 12:35 | tom.to       
好文...
先回复在看完

  回复  引用  查看    
#85楼 2011-08-22 08:52 | 代维雅       
ie8以后,浏览器有了多页签,如果一个浏览器打开多个应用程序,会出现cookies冲突,怎么办???
  回复  引用  查看    
#86楼 2011-08-22 09:30 | 南京.王清培       
好文,多谢分享。楼主辛苦。赞
  回复  引用  查看    
#87楼 [ 楼主] 2011-08-22 12:29 | Fish Li       
@代维雅
你会在不同的页面写同一个名字的Cookie ?
如果真是这样,我还真没什么好办法。

  回复  引用  查看    
#88楼 [ 楼主] 2011-08-22 12:31 | Fish Li       
@南京.王清培
多谢【赞】我博客。哈哈。

  回复  引用  查看    
#89楼 2011-08-22 14:17 | 代维雅       
@Fish Li
引用 Fish Li:
@代维雅
你会在不同的页面写同一个名字的Cookie ?
如果真是这样,我还真没什么好办法。


我确实遇到这样的情况,如果用两个账号,在一个浏览器的多个页签登录,浏览器就会以最后的一个登录的为准。
  回复  引用  查看    
#90楼 2011-08-22 14:53 | 寒@鹏       
再一次 深入学习了
  回复  引用  查看    
#91楼 [ 楼主] 2011-08-22 17:53 | Fish Li       
@代维雅
你这种情况应该只会发生在测试情景中,建议用二个浏览器来操作吧。

  回复  引用  查看    
#92楼 2011-08-27 23:37 | 岂可       
不错,学习了。
  回复  引用  查看    
#93楼 2011-08-28 23:25 | 草珊瑚       
@Fish Li
如何在C#发请的请求中使用Cookie,
我一直以为是请求时连带Cookie发送过去,
原来是请求后,响应的Cookie设置读取呀。

  回复  引用  查看    
#94楼 2011-09-07 11:53 | kkun       
大师风范,讲得很透彻!
  回复  引用  查看    
#95楼 2011-09-08 11:52 | Tony_Zhang       
LZ辛苦 学习了
  回复  引用  查看    
#96楼 2011-09-21 13:23 | 小 刚Ⅰ       
为什么我用ChromeCookiesView看不到session用的cookie呢,这个cookie应该是存在浏览器中而不是硬盘文件的吧
  回复  引用  查看    
#97楼 [ 楼主] 2011-09-21 17:37 | Fish Li       
@小 刚Ⅰ
1. Chrome我基本不用,所以这个问题我回答不了。
2. 你换个角度想一下:如果cookie保存在浏览器中,浏览器程序关闭后,又怎么办?

  回复  引用  查看    
#98楼 2011-09-22 10:49 | 小 刚Ⅰ       
如果存放sessionid的cookie不是在浏览器中,那么为什么硬盘中不会产生session的相关cookie

浏览器每次重新打开都会产生一个新的sessionid, 关闭后如果存放在服务器中的session还没有过期,那么下次访问还是有效的。不过sessionid已经变了

个人见解

  回复  引用  查看    
#99楼 [ 楼主] 2011-09-22 12:18 | Fish Li       
Cookie有临时的和永久保存的。
  回复  引用  查看    
#100楼 2011-10-27 12:17 | Rainbow       
是篇好文章。用心写得文章。
  回复  引用  查看    
#101楼 2011-11-01 13:45 | 浪长街       
楼主回答粉丝的问题也很用心,不关注都不行
  回复  引用  查看    
#102楼 2011-11-01 16:07 | 拉拉叟       
private static string SendHttpRequestGet(string url, Encoding encoding,
CookieContainer cookieContainer)
{
if( string.IsNullOrEmpty(url) )
throw new ArgumentNullException("url");

if( encoding == null )
throw new ArgumentNullException("encoding");

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.CookieContainer = cookieContainer;

using( WebResponse response = request.GetResponse() ) {
using( StreamReader reader = new StreamReader(response.GetResponseStream(), encoding) ) {
return reader.ReadToEnd();
}
}
}

private void SendHttpDEMO()
{
StringBuilder sb = new StringBuilder();
CookieContainer cookieContainer = new CookieContainer();

string url = "http://www.taobao.com";
SendHttpRequestGet(url, Encoding.Default, cookieContainer);

// 后面可以继续发起HTTP请求,此时将会包含上次从服务器写入的Cookie
//SendHttpRequestGet("同域名下的其它URL", Encoding.Default, cookieContainer);

// 至此,我们可以显示取得了哪些Cookie
CookieCollection cookies = cookieContainer.GetCookies(new Uri(url));
if( cookies != null ) {
foreach( System.Net.Cookie cookie in cookies )
sb.AppendLine(cookie.ToString());
}
txtCookies.Text = sb.ToString();
}
///
有个小地方 百思不得其解 望解答
这段代码中 cookieContainer对象只是在request.CookieContainer = cookieContainer; 这行代码中赋值给request.CookieContainer
为什么后来cookieContainer里面有对象了呢?

  回复  引用  查看    
#103楼 [ 楼主] 2011-11-01 17:37 | Fish Li       
@拉拉叟
CookieContainer是个保存Cookie的容器,.net framework会在收到cookie后写到里面去的。

  回复  引用  查看    
#104楼 [ 楼主] 2011-11-01 17:38 | Fish Li       
引用 浪长街:楼主回答粉丝的问题也很用心,不关注都不行

谢了。
  回复  引用  查看    
#105楼 2011-11-01 17:39 | 拉拉叟       
谢谢楼主细心的解答
  回复  引用  查看    
#106楼 2011-11-09 17:18 | Domi.Z       
hi,fish:
请问你文章最后说HttpRequest.Cookies 与HttpResponse.Cookies 会有关系,实在有点摸不着头脑,为什么会有这样的结果呢?

  回复  引用  查看    
#107楼 [ 楼主] 2011-11-09 18:43 | Fish Li       
@Domi.Z
我的另一篇博客【我心目中的Asp.net核心对象】有介绍。

  回复  引用  查看    
#108楼 2011-11-28 15:46 | 丫头骗子       
写的很好,学习了。
  回复  引用  查看    
#109楼 2011-12-21 08:57 | 小东1989       
写的很好,使我加深对cookie的理解,学习中!!!
  回复  引用  查看    
#110楼 2012-01-04 09:40 | cwg2010       
楼主的排版简洁,内容也不错!必须顶!
  回复  引用  查看    
#111楼 [ 楼主] 2012-01-04 20:12 | Fish Li       
@cwg2010
多谢

  回复  引用  查看    
#112楼 2012-01-14 21:15 | xu_happy_you       
很好,很强大!收藏了!
  回复  引用  查看    
#113楼 2012-01-16 16:44 | dreamhappy       
一个公共方法的类库,每个方法都有注释 (标准的///形式),编译成dll后,在其他项目中引用这个类库,但是方法都没有注释,怎么样才能看到注释呢?
  回复  引用  查看    
#114楼 [ 楼主] 2012-01-16 22:38 | Fish Li       
@dreamhappy
你要生成包含注释的XML文件的。
项目 -> 属性 -> 生成选项卡中,选择“XML文档文件”

  回复  引用  查看    
#115楼 2012-01-30 15:20 | 刺客之家       
今天发现了一个特点,就是只有当请求的页面使用了Session对象时,asp.Net才为该请求返回一个SetCookie的Response头信息.
  回复  引用  查看    
#116楼 2012-02-01 11:40 | Domi.Z       
hi, fish。我问一下,可以不可以把相互依赖的字段 (例如城市ID和国家ID) 放入Cookie? 我目前只把城市ID放到Cookie中避免潜在攻击,但这又给系统增加了复杂性(每个用到国家ID的地方都要先通过城市ID去查找)。目前我的确还没有遇到过有用户篡改Cookie,请问你有没有遇到过类似的需求,你是如何处理的?
  回复  引用  查看    
#117楼 [ 楼主] 2012-02-01 12:19 | Fish Li       
@Domi.Z
不好意思,不太明白你的业务需求。
使用Cookie时只要记住:它只合适保存较小的数据,且对安全性的要求应该不高。在这个前提条件下,你放什么数据,理论上都是可以的。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值