zoukankan      html  css  js  c++  java
  • 钻牛角尖之Request.Cookies与Response.Cookies

           昨天无聊在园子里看到一篇新闻 8岁小学生表白遭拒:被一部iPhone打败 ,看到这样文章出现在技术园子里(估计就因为一个iphone的关键字),并且比同时间的新闻阅读量高出很多,就发出了程序员有多无聊的感叹,其实也有自嘲的性质(因为最近确实有点迷惘,无法定下心看一些技术文章,特别长一点的,看到后往往收藏或mark了事,安慰自己以后看,其实很少再去看了),果然遭到了园子里同学的无情嘲讽,哈哈,无聊的程序员是多。。。

          除此之外,也做了点“正事”,看了园子里人气很高的 fish li 的 我心目中的Asp.net核心对象 ,实话说,毕竟也工作了几年,对文章里提到一些东西还是了解的,但是在看到文章中提到:

    HttpRequest有一个Cookies属性,MSDN给它的解释是:“获取客户端发送的 Cookie 的集合。”,这次MSDN的解释就不完全准确了。

    然后贴了一个例子:

    protected void Page_Load(object sender, EventArgs e)
    {
        string key = "Key1";
    
        HttpCookie c = new HttpCookie(key, DateTime.Now.ToString());
        Response.Cookies.Add(c);
    
    
        HttpCookie cookie = Request.Cookies[key];
        if( cookie != null )
            this.labResult.Text = cookie.Value;
    
    
        Response.Cookies.Remove(key);
    }

    这个例子说明:Request.Cookies不仅来自于客户端发来的cookie集合,还会受到Response.Cookies修改的影响。

    以前这块还真没有仔细了解过,认为这两个一个就是获取客户端传来的cookie的集合,一个就是我们想输出到客户端的cookie的集合,虽然都是cookie,应该不相干的,但是竟然出现了这样的关联,这给我的一个颠覆:这两个集合引用的是同一个实例?!

    Request.Cookies、Response.Cookies是同一个人的两个身份吗

    为什么这样假设,因为它能很好的解释上面的结果,但是实际是这样吗?我也做了实验:

    protected void Page_Load(object sender, EventArgs e)
    {
        HttpCookieCollection hccRequest = Request.Cookies;
        HttpCookieCollection hccResponse = Response.Cookies;
    
    
        string key = "Key1";
        HttpCookie c = new HttpCookie(key, "1");
        hccResponse.Add(c);
        hccResponse.Remove(key);
    
    
        String key2 = "key2";
        HttpCookie cookie = new HttpCookie(key2,"2");
        hccRequest.Add(cookie);
    
    }

    代码比较简单,然后F5,F10单步调试,查看监视信息。

    在代码执行了前两行时,在即时窗口进行了以下的测试:

    image

    结果让我有些失望,两个不是同一个东西。

    不灰心,继续执行,具体每步之后的监视信息这里就不贴了,有兴趣的同学自己试下,上结果:我们对Response.Cookies添加、删除都会及时的反映到Request.Cookies,但是对Request.Cookies的添加操作时,Response.Cookies没有反应。

    这样结论就有了:两者是两个实例,但为什么Response.Cookies会影响Request.Cookies?!

    为什么Response.Cookies会影响Request.Cookies

    再往下,就要借助.net reflector。

    先看一下,Request.Cookies的代码:

    public HttpCookieCollection Cookies
    {
        get
        {
            if (this._cookies == null)
            {
                this._cookies = new HttpCookieCollection(null, false);
                if (this._wr != null)
                {
                    this.FillInCookiesCollection(this._cookies, true);
                }
            }
            if (this._flags[4])
            {
                this._flags.Clear(4);
                this.ValidateCookieCollection(this._cookies);
            }
            return this._cookies;
        }
    }
    

    在HttpRequest内部,对应_cookies的私有变量,再深入讨论这段代码之前,我们还是先看一下Response.Cookies的代码:

    public HttpCookieCollection Cookies
    {
        get
        {
            if (this._cookies == null)
            {
                this._cookies = new HttpCookieCollection(this, false);
            }
            return this._cookies;
        }
    }

    在HttpResponse内部,也是对应一个_cookies的私有变量,不过从这两段代码,我们更确定了它们不是同一个人,它们都通过new HttpCookieCollection来初始化了自己,创建了一个新的实例。

    接下来看一下它们实例化的构造函数:

    internal HttpCookieCollection(HttpResponse response, bool readOnly) : base(StringComparer.OrdinalIgnoreCase)
    {
        this._response = response;
        base.IsReadOnly = readOnly;
    }

    关键在第一个参数,它要求是一个HttpResponse的实例,Response.Cookies实例化时传入自己的Response是应该的,但是Request.Cookies却传入的是null。

    为什么说它是关键,接下来看下HttpCookieCollection的Add操作:

    public void Add(HttpCookie cookie)
    {
        if (this._response != null)
        {
            this._response.BeforeCookieCollectionChange();
        }
        this.AddCookie(cookie, true);
        if (this._response != null)
        {
            this._response.OnCookieAdd(cookie);
        }
    }
    
    

    这时我们可以确定一些事情了,由于Request.Cookies传入null,这段代码对于它来说,只是执行了AddCookie,实际的代码就只是添加了一个cookie项;而对于Response.Cookies,还要执行BeforeCookieCollectionChange和OnCookieAdd的操作,重点在OnCookieAdd操作:

    internal void OnCookieAdd(HttpCookie cookie)
    {
        this.Request.AddResponseCookie(cookie);
    }

    竟然去执行了Request的AddResponseCookie操作:

    internal void AddResponseCookie(HttpCookie cookie)
    {
        if (this._cookies != null)
        {
            this._cookies.AddCookie(cookie, true);
        }
        if (this._params != null)
        {
            this._params.MakeReadWrite();
            this._params.Add(cookie.Name, cookie.Value);
            this._params.MakeReadOnly();
        }
    }

    而这个操作里又对_cookies进行了修改,从上边我们知道Request.Cookies内部引用的就是它,因此从这里就从代码上解释了:我们对Response.Cookies添加、删除都会及时的反映到Request.Cookies,但是对Request.Cookies的添加操作时,Response.Cookies没有反应。

    另外,我们在Request.Cookies的代码里看到有FillInCookiesCollection(this._cookies, true)的操作,代码太长,只贴下它的声明:

    internal void FillInCookiesCollection(HttpCookieCollection cookieCollection, bool includeResponse)

    这个操作就是从客户端传来的cookie信息中去填充Request.Cookies集合,看第二个参数bool includeResponse,是否包含response,传入的是true说这个填充,不只是填充了Request.Cookies集合,也填充了Response.Cookies集合,这也就解释了:我们每次拿到的未经操作的这两个集合总是包含同样的值,尽管是两个不同的实例。

     

    更正:实在对不起,自己后来做个实验发现,填充Request.Cookies集合,并没有填充了Response.Cookies集合。贴上一段FillInCookiesCollection用到includeResponse的代码:

    if (includeResponse && (this.Response != null))
            {
                HttpCookieCollection cookies = this.Response.Cookies;
                if (cookies.Count > 0)
                {
                    HttpCookie[] dest = new HttpCookie[cookies.Count];
                    cookies.CopyTo(dest, 0);
                    for (int i = 0; i < dest.Length; i++)
                    {
                        cookieCollection.AddCookie(dest[i], true);
                    }
                }
            }
    其实includeResponse的作用是填充Request.Cookies集合时是否把Response.Cookies集合中的数据也填充到Request.Cookies集合里。这段代码的作用就是把Response.Cookies集合中的数据也填充到Request.Cookies集合。这样:Response.Cookies每次都是空的,除非你主动操作了,如果操作,就去修改之前的cookie,没有就保持原来的cookie不变。

    结论:Request.Cookies,Response.Cookies是两个不同的实例,两个集合实例的添加、删除操作就不同了,对Response.Cookies添加、删除都会及时的反映到Request.Cookies,对Request.Cookies的添加、删除操作,Response.Cookies没有反应(但是因为相同的键对应的值是引用类型,对这些值进行的修改会相互影响)。

    疑惑

          虽然了解了事情的真相,但是有了更多的疑惑:为什么要这样设计?为什么之后还要同步Response.Cookies的添加删除到Request.Cookies呢,有啥意义呢,要输出的cookie竟然影响了请求传送的cookie集合,反而产生了“Request.Cookies是获取客户端发送的 Cookie 的集合”解释不准确的尴尬。

  • 相关阅读:
    Python菜鸟之路:Python基础-线程、进程、协程
    Python菜鸟之路:Python基础-Socket编程-2
    Python菜鸟之路:Python基础-Socket基础-1
    react-native 使用 antd-mobile-rn UI进行开发app
    Java基础
    Java基础
    Java基础
    Java基础
    Java基础
    Java基础
  • 原文地址:https://www.cnblogs.com/forcertain/p/2801224.html
Copyright © 2011-2022 走看看