• 关于Cookies与Session系列一


    这两个东西,最近项目操作的比较少,不过这两个在Web项目开发中一直都扮演着很重要的角色,有时有些细节会不小心就遗忘掉。

    Cookies  的概述

    Cookies是由服务器端生成,发送给客户端,用来保存一些数据文本文件。在用户进行网页浏览时,这家伙会在客户端与服务器之前传递,常用作身份的验证、用户会话识别或存储小型数据。由于cookies是保存在客户端,那么就意味着用户可以修改和读取,因此有人利用木马、病毒窃取用户Cookies并获得用户信息,所以,作为开发人员,Cookies不适合保存重要或者涉及隐私的内容,除非你加密。(当然,作为用户,定期清理这些垃圾是一个好习惯~)

     

    Cookies 的限制

    大多数浏览器支持最大为4096个字节的Cookie,所以Cookie不适合保存大数据。 浏览器也会限制同一个站点下的Cookies数量,一般为20个,超出这个数量的话,旧的Cookie将会被丢弃。 用户可以禁用Cookie,如果禁用后会影响Session的信息保存(相关问题在后续会讲到)

    Cookies  的操作

    由System.Web.HttpCookie中可以看到.net 提供的Cookie的属性及方法

    // 摘要:
        //     提供创建和操作各 HTTP Cookie 的类型安全方法。
        public sealed class HttpCookie
        {
            // 摘要:
            //     创建并命名新的 Cookie。
            //
            // 参数:
            //   name:
            //     新 Cookie 的名称。
            public HttpCookie(string name);
            //
            // 摘要:
            //     创建和命名新的 Cookie,并为其赋值。
            //
            // 参数:
            //   name:
            //     新 Cookie 的名称。
            //
            //   value:
            //     新 Cookie 的值。
            public HttpCookie(string name, string value);
    
            // 摘要:
            //     获取或设置将此 Cookie 与其关联的域。
            //
            // 返回结果:
            //     要将此 Cookie 与其关联的域名。默认值为当前域。
            public string Domain { get; set; }
            //
            // 摘要:
            //     获取或设置此 Cookie 的过期日期和时间。
            //
            // 返回结果:
            //     此 Cookie 的过期时间(在客户端)。
            public DateTime Expires { get; set; }
            //
            // 摘要:
            //     获取一个值,通过该值指示 Cookie 是否具有子键。
            //
            // 返回结果:
            //     如果 Cookie 具有子键,则为 true;否则为 false。默认为 false。
            public bool HasKeys { get; }
            //
            // 摘要:
            //     获取或设置一个值,该值指定 Cookie 是否可通过客户端脚本访问。
            //
            // 返回结果:
            //     如果 Cookie 具有 HttpOnly 属性且不能通过客户端脚本访问,则为 true;否则为 false。默认值为 false。
            public bool HttpOnly { get; set; }
            //
            // 摘要:
            //     获取或设置 Cookie 的名称。
            //
            // 返回结果:
            //     除非构造函数另外指定,否则默认值为 null 引用(在 Visual Basic 中为 Nothing)。
            public string Name { get; set; }
            //
            // 摘要:
            //     获取或设置要与当前 Cookie 一起传输的虚拟路径。
            //
            // 返回结果:
            //     要与此 Cookie 一起传输的虚拟路径。默认值为当前请求的路径。
            public string Path { get; set; }
            //
            // 摘要:
            //     获取或设置一个值,该值指示是否使用安全套接字层 (SSL)(即仅通过 HTTPS)传输 Cookie。
            //
            // 返回结果:
            //     如果通过 SSL 连接 (HTTPS) 传输 Cookie,则为 true;否则为 false。默认为 false。
            public bool Secure { get; set; }
            //
            // 摘要:
            //     获取或设置单个 Cookie 值。
            //
            // 返回结果:
            //     Cookie 的值。默认值为 null 引用(在 Visual Basic 中为 Nothing)。
            public string Value { get; set; }
            //
            // 摘要:
            //     获取单个 Cookie 对象所包含的键值对的集合。
            //
            // 返回结果:
            //     Cookie 值的集合。
            public NameValueCollection Values { get; }
    
            // 摘要:
            //     获取 System.Web.HttpCookie.Values 属性的快捷方式。此属性是为了与以前的 Active Server Pages (ASP)
            //     版本兼容而提供的。
            //
            // 参数:
            //   key:
            //     Cookie 值的键(索引)。
            //
            // 返回结果:
            //     Cookie 值。
            public string this[string key] { get; set; }
    System.Web.HttpCookie(System.Web.dll, v4.0.0.0)

    简单的操作如下

    public ActionResult Index()
            {  
                var cookie = new HttpCookie("MyCookieName", "string value");
                //简单的Cookie
                Response.Cookies.Add(cookie); 
    
                var testCookies = new HttpCookie("MyCookiesInfo");
                //默认属性
                testCookies.Value = "丰富的Cookies";
                //TestCookies.Domain = "testlocalhost";默认为当前网站跟域,如localhost,但如果你想设置域为testlocalhost,嘻嘻,自己试试
                testCookies.Name = "123456"; //这里重置了该Cookies的名称,改为123456
                //额外的属性
                testCookies["TestAttr1"] = "再来个属性";
                testCookies["TestAttr2"] = "再来个属性2";
                //设置超时时间
                testCookies.Expires = DateTime.Now.AddHours(1);
                Response.Cookies.Add(testCookies);
                return View();
            }
    
            public ActionResult About()
            {
                string test = Request.Cookies["MyCookieName"].Value;
                string test2 = Request.Cookies["123456"].Value;
                string test3 = Request.Cookies["123456"]["TestAttr1"];
                Response.Write(test + "|" + test2 + "|" + test3 + "|" + Request.Cookies["123456"].Expires.ToString());
                return View();
            }
     
    About页面输出的结果是 string value|丰富的Cookies&TestAttr1=再来个属性&TestAttr2=再来个属性2|再来个属性|0001/1/1 0:00:00 ­­

    这里可以看到一个cookie操作的特性
    当浏览器向服务器发送 Cookie 信息时,并不包括有效期信息。(Cookie 的 Expires 属性始终返回值为 0 的日期时间值。)
    即服务器不能获取cookie的有效时间来判断cookie是否已经过期。
    那我们能不能改变cookie的有效时间让它提前过期呢?我们修改About的代码如下
               string test = Request.Cookies["MyCookieName"].Value;

                Request.Cookies["MyCookieName"].Value = "我要修改属性啦!";
                Response.Cookies["MyCookieName"].Expires = DateTime.Now.AddDays(-1);


                string test2 = Request.Cookies["123456"].Value;
                string test3 = Request.Cookies["123456"]["TestAttr1"];
              
                Request.Cookies["123456"].Value = "我要修改属性啦!";

    在执行Index时,cookie信息如下

    到About页面时

    只剩下123456这个cookie了,因为我们设置MyCookieName的超时时间比当前时间小,因此客户端自动将这个cookie删除了。

    但请注意,123456的cookie值没有改变!!为什么??别急,我们先来看看我们在操作上述代码时,客户端与服务端是怎么沟通的?对,Http协议。

    Http协议的详细内容就不在这啰嗦了,请去找度娘(屌丝程序员的最爱)。研究协议的最好方法还是抓包,抓包工具很多,以后应该会针对http协议有一篇总结,到时再详细说吧。

    以下是请求Index时的一个抓包的部分截图

    我们可以看到,服务端在HTTP的响应头中通过Set-Cookie】的响应头来进行Cookie的设置
    那么我们在访问About时,抓包截图如下


    可以看到产生了一个Set-Cookie】的响应头,将MyCookieName的Expires时间改变了(比较123456的Expires即可知MyCookieNameExpires变得比当前时间小,故删除操作是客户端自己完成的),因此,客户端就只剩下123456这个cookie了,那为什么123456的值没有改变呢?怎么改变呢?我们再来修改About的代码,增加如下代码
              var temp = new HttpCookie("123456");
                temp = Request.Cookies["123456"];
                temp["TestAttr1"] = "真的要改变属性值啦!";
                Response.Cookies.Add(temp);
    
    

    然后重新由Index页面跳转到About页面

    抓包截图为

    没错,这样才会产生一个Set-Cookie】的响应头
    因此操作cookie的另外一个特性为
    服务端不能直接改变客户端的cookie值,包括超时时间也不能直接修改,需要重新建立一个对应名称的Cookie,然后重新对该Cookie下的的属性赋值,再添加到httpContext中,
    超时时间也一样,只能重写
    虽然修改不了Cookie,但可以取得,那服务端是如何拿到客户端的Cookie信息呢?
    细心的朋友发现了刚才抓包截图中左侧为客户端请求头,很明显客户端(浏览器)在每次请求时会把cookie信息装进请求头中,这里还需要注意一点,我们保存在浏览器上的cookie非常多,难道每次请求都会把所有的cookie放到请求头去么?答案是否定的。
    浏览器会检查当前要请求的域名以及目录, 只要这二项目与Cookie对应的Domain和Path匹配,才会发送。对于Domain则是按照尾部匹配的原则进行的。
     
    最后补充一下和Cookie相关的一些操作
    校验浏览器是否支持Cookies,不支持时可以提示用户
        if (Request.Browser.Cookies)
            {
                //浏览器支持cookies,继续coding......
            }
            else
            {
                //浏览器不支持cookies,那么弹出提示信息或者重定向到新页面进行处理
            }    

    Js也能操作Cookies的,简单的例子如下

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

    读取的效果为

    如果想对读取结果进行解析,请自行处理一下。

    写的效果为



    在前面的代码中,如果你设置 TestCookies.Domain = "testlocalhost" 该cookie将不会被创建,大家能说说是什么原因么?

    
    

     

  • 相关阅读:
    使用日历控件的一些体会(downmoon)
    带附加条件的NewID()用法
    微软的招聘哲学——做微软人的五大核心素质(摘自《微软360度》)
    彻底禁用fckEditor的上传功能(含防止Type漏洞问题)
    Remote Access Connection Manager 服务因下列错误而停止解决办法
    GridView如何更新批量数据和单条记录?
    .net1.1与.net2.0在加载ascx文件的控件时有所不同(Downmoon)
    牛羊吃草问题求解(downmoon)
    c#操作ecxel的一些资源(downmoon搜集)
    安装sql2008 enterprise (English正式版)图解
  • 原文地址:https://www.cnblogs.com/endysaiwang/p/3719814.html
Copyright © 2020-2023  润新知