资讯专栏INFORMATION COLUMN

谈谈我熟悉又陌生的cookie

fizz / 1705人阅读

摘要:前言大概是我的业务领域比较狭窄的原因我总是会听说却很少在实际的开发中应用或者实践过它今天刚好看到高级程序设计第三版的数据存储部分说到了这里就对做一个深入访谈希望和我一样对似曾相识的朋友可以真正的熟悉并学会利用来服务我们的业务定义是服务器为了

前言

大概是我的业务领域比较狭窄的原因,我总是会听说cookie,却很少在实际的开发中应用或者实践过它,今天刚好看到<>的数据存储部分,说到了cookie,这里就对cookie做一个深入访谈,希望和我一样对cookie似曾相识的朋友可以真正的熟悉cookie,并学会利用cookie来服务我们的业务.^_^^_^

Cookie 定义

cookie,是服务器为了辨别用户身份,进行session跟踪而存储在用户本地终端上的数据(通常经过加密).

限制

域名限制

因为cookie一般用于与服务器进行交互,所以它一般存放在对应的域名下.当设定了一个cookie后,再给创建它的域名发送请求时,都会包含这个cookie,这个限制确保了储存在cookie中的信息只能让批准的接受者访问,而无法被其他域访问.

个数限制
由于cooki是存储在客户端计算机上的,还加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间.每个域的cookie总数是有限的,不过浏览器之间各有不同.

IE7和之后的版本每个域名最多50个.

Firefox限制每个域最多50个cookie

Opera限制每个域最多30个cookie

Safari 和Chrome 对每个域的cookie数量没有硬性规定.

当超过单个域名限制之后还要在设置cookie,浏览器会清除以前设置的cookie.IE和Opera会删除最近最少使用过的cookie.所以考虑cookie限制非常重要,避免出现不可预期的后果.

尺寸限制
浏览器中对于cookie的尺寸也有限制,大多数浏览器是4KB的长度限制,尺寸限制影响一个域下所有的cookie,而并非每个cookie多带带限制.
如果你尝试创建查过最大限制的cookie,那么该cookie会被悄无声息地丢掉.

cookie的构成

cookie由浏览器保存的以下几块信息构成.

名称(name): 一个唯一确定cookie的名称.

值(value): 存储在cookie中的字符串值.

域(domain): cookie对于哪个域是有效的,控制只有向该域发送的请求才会包含这个cookie.

路径(path): 对于指定域中的哪个路径,应该向服务器发送cookie.

失效时间(expires): 表示cookie何时会被删除的时间戳,没有设置则默认是浏览器会话结束时,即将所有cookie删除,若设置的失效日期是以前的时间,则cookie会被立刻删除.

安全标志(secure): 制定后,cookie只有在使用SSL链接的时候才会发送到服务器,即https请求才可以发送cookie.

注意发送cookie的时候只会发送cookie的名和值才会被发送,其他值只会cookie信息的描述.

cookie的使用 使用场景

常用场景: cookie一般用来做登录验证,用户登陆的时候讲用户名和密码传入到服务器端,服务器会返回将用户相关的认证信息,然后由服务器将这些信息写入cookie或者由前端使用js操作cookie将这些信息写入到cookie中(如果服务器通过Set-Cookie的方式直接写入则不需要前端的参与,前端是无感知的),登陆成功以后的用户在该域名下的访问都会在请求中发送cookie,作为该用户的身份标识.我们这里主要讨论的是前端使用js操作cookie的情况.

不常用场景: 我们也可以用js操作cookie,在cookie上存储我们临时需要的用于页面交互的变量,这个时候cookie就充当了sessionStorage或者localStorage的角色.

操作cookie

由于JavaScript中读写cookie不是非常直观,常常需要写一些函数来简化cookie的功能.基本的操作有三种: 读取,写入,删除;

说明: 我不知道看这篇文章的朋友是不是了解这些操作cookie的方法,如果不了解,我建议你先想一想,然后尝试着自己去写,然后感兴趣的话再来看看我的代码,也可以分享到评论区,我们一起来看看这些实现方法的优劣,不知道不同思想的碰撞会不会擦出奇妙的火花呢? 很期待奥~

封装的操作cookie的代码如下:

const CookieUtil = {
    // 获取cookie 接受的参数 cookie的名称
    get: function(name) {
        var cookieName = encodeURIComponent(name) + "=",
            cookieStart = document.cookie.indexOf(cookieName),
            cookieValue = null;
        if(cookieStart !== -1) {
            var cookieEnd = document.cookie.indexOf(";",cookieStart);
            if(cookieEnd == -1) {
                cookieEnd = document.cookie.length;
            }
            cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.LENGTH, cookieEnd));
        }
        return cookieValue;
    },
    // 设置cookie, 接收参数: cookie的名称, cookie的值, 
    // 可选的用于执行cookie何时应被删除的Date对象,cookie的可选的URL路径, 可选的域和是否要添加secure标志的布尔值
    set: function (name, value, expires, path, domain, secure) {
        var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
        if(expires instanceof Date) {
            cookieText += "; expires=" + expires.toGMTString();
        }
        if(path) {
            cookieText += "; path=" + path;
        }
        if(domain) {
            cookieText += "; domain=" + domain;
        }
        if(secure) {
            cookieText += "; secure";
        }
        document.cookie = cookieText;
    },
    // 删除cookie的方法, 接收的参数: 要删除的cookie的名称,可选的路径参数,可选的域参数和可选的安全参数
    unset: function (name, path, domain, secure) {
        // 将某个cookie的过期时间早于当前时间,则会被立刻删除,该方法设置失效时间为1970年1月1日
        this.set(name, "", new Date(0), path, domain, secure);
    }
}

// 设置cookie
CookieUtil.set("name", "Nicholas");
CookieUtil.set("book", "Professional JavaScript");

// 读取cookie的值
CookieUtil.get("name");
CookieUtil.get("book");

// 删除cookie
CookieUtil.unset("name");
CookieUtil.unset("book");
子cookie

为了绕开浏览器的单域名下的cookie数限制,一些开发人员使用了一种成为子cookie的改变,子cookie是存放在单个cookie中的更小段的数据,通常是多个名称值对的形式.子cookie对常见的格式如下所示:
namename1=value1&name2=value2&name3=value3&name4=value4&name5=value5
子cookie一般也以查询字符串的格式进行格式化,然后这些值可以使用单个cookie进行储存和访问,而非对每个名称-值对儿使用不同的cookie存储,最后网站或者web应用程序可以无需大到单域名cookie上限也可以存储更加结构化的数据.
为了更好的操作子cookie,必须建立一系列新方法,子cookie的解析和序列化会因子cookie的期望用途而略有不同并更加复杂些,例如,要获得一个子cookie,首先要遵循与获得cookie一样的基本步骤,但是在解码cookie值之前,需要操作字符串,遍历数组之类的操作来找出子cookie的信息.

说明: 我不知道看这篇文章的朋友是不是了解这些操作cookie的方法,如果不了解,我建议你先想一想,然后尝试着自己去写,然后感兴趣的话再来看看我的代码,也可以分享到评论区,我们一起来看看这些实现方法的优劣,不知道不同思想的碰撞会不会擦出奇妙的火花呢?

操作子cookie的方法如下:

// 操作子cookie的一组方法
var SubCookieUtil = {
    // 获取cookie, 接收两个参数,cookie名和子cookie名
    // 如果不穿子cookie名,则是普通的获取方法,如果传了,则取对应子cookie名的value.
    get: function (name, subName) {
        var subCookies = this.getAll(name);
        if(subCookies) {
            return subCookies[subName];
        } else {
            return null;
        }
    },
    // 判断如果cookie中name对应的value不包含子cookie,
    // 则返回解码后的cookieValue,如果包含子cookie,则返回处理后的result对象
    getAll: function (name) {
        var cookieName = encodeURIComponent(name) + "=",
            cookieStart = document.cookie.indexOf(cookieName),
            cookieEnd,
            result={},
            cookieValue= null,
            i,len,subCookies="",
            parts = [];
        if(cookieStart !== -1) {
            cookieEnd = document.cookie.indexOf(";", cookieStart);
            if(cookieEnd == -1) {
                cookieEnd = document.cookie.length;
            }
            cookieValue = document.cookie.substring(cookieStart + cookieName.length, cookieEnd);
            if(cookieValue.length > 0) {
                if(cookieValue.indexOf("&") > -1) {
                    subCookies = cookieValue.split("&");
                    console.log("get subCookies",subCookies);
                    for(i = 0,len = subCookies.length; i < len; i++) {
                        parts = subCookies[i].split("=");
                        result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
                    }
                } else {
                    parts = cookieValue.split("=");
                    result[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1])
                }
                return result;
            }
        }
        return null;
        
    },
    // 同样的,要设置子cookie,也有新的set方法
    set: function(name, subName, value, expires, path, domain, secure) {
        
        var subCookies = this.getAll(name) || {};
        subCookies[subName] = value;
        this.setAll(name, subCookies, expires, path, domain, secure);
    },
    setAll: function(name, subCookies, expires, path, domain, secure) {
        var cookieText = encodeURIComponent(name) + "=",
            subCookieParts = [],
            sub, result;
        // 将subCookies对象里的cookie值对编码,并放进subCookieParts数组中
        for(sub in subCookies) {
            if(subCookies.hasOwnProperty(sub)) {
                subCookieParts.push(encodeURIComponent(sub)+ "=" + encodeURIComponent(subCookies[sub]));
            }
        }
        if(subCookieParts.length > 0) {
            cookieText += subCookieParts.join("&");
            if(expires instanceof Date) {
                cookieText += "; expires=" + expires.toGMTString();
            }
        } else {
            cookieText += "; expires=" + (new Date(0)).toGMTString();
        }
        if(path) {
            cookieText += "; path=" + path;
        }
        if(domain) {
            cookieText += "; domain=" + domain;
        }
        if(secure) {
            cookieText += "; secure";
        }
        document.cookie = cookieText;   
    },
    // 删除cookie 删除单个cookie
    unset: function(name, subName, path, domain, secure) {
        var subCookies = this.getAll(name);
        subCookies[subName] ? delete subCookies[subName] : "";
        this.setAll(name, subCookies, null, path, domain, secure);
    },
    //删除cookie  删除多个cookie  
    unsetAll: function (name, path, domain, secure) {
        this.setAll(name, null, new Date(0), path, domain, secure);
    }  
}

// 假设 document.cookie = "data=name=Nicholas&book=Professional%20JavaScript"
// 设置两个cookie
SubCookieUtil.set("xiaosisi", "name", "Nicholas");
SubCookieUtil.set("xiaosisi", "book", "Professional JavaScript");
SubCookieUtil.set("xiaosisi", "sisisi", "撕撕撕");
// 设置全部子cookie和失效日期
SubCookieUtil.setAll("xiaosisi", {name: "Nicholas", book:"Professional JavaScript",  sisisi: "撕撕撕"}, new Date("2018-10-25"));
// 修改名字的值,并修改失效日期
SubCookieUtil.setAll("xiaosisi", "name", "MIrascl", new Date("2018-11-25"));

// 删除名为sisisi的子cookie
SubCookieUtil.unset("xiaosisi", "sisisi");
// 删除整个cookie
SubCookieUtil.unsetAll("xiaosisi");
总结

关于cookie有两点需要注意的地方:

第一: 由于所有的cookie都会由浏览器作为请求头发送,所以在cookie中存储大量信息会影响到特定域的请求性能,cookie信息越大,完成对服务器请求的时间也就越长.尽管浏览器对cookie的大做了限制,不过最好还是尽可能在cookie中少存储信息,以免影响性能.

第二:一定不要在cookie中存储重要和敏感的数据.cookie的存储不是很安全,其中包含的任何数据都可以被他人访问,重要的用户信息不建议存储在cookie里.

如果读者们有关于cookie的比较好的使用策略欢迎在评论区留言或者私信我奥~共同进步是最让人开心的事儿呢~~~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/95448.html

相关文章

  • 前端基础

    摘要:谈起闭包,它可是两个核心技术之一异步基于打造前端持续集成开发环境本文将以一个标准的项目为例,完全抛弃传统的前端项目开发部署方式,基于容器技术打造一个精简的前端持续集成的开发环境。 这一次,彻底弄懂 JavaScript 执行机制 本文的目的就是要保证你彻底弄懂javascript的执行机制,如果读完本文还不懂,可以揍我。 不论你是javascript新手还是老鸟,不论是面试求职,还是日...

    graf 评论0 收藏0
  • 摩拜前端周刊第8期

    摘要:地址前端词典提高幸福感的个技巧推荐文章介绍了个更加简洁优雅的使用技巧。这些技巧确实在实际开发中十分常用,作者总结的很好,特别是针对降级问题又学到了一个新思路。值得奋战在一线的攻城狮们阅读学习。Ladies and 乡亲们,摩拜前端周刊起航啦~ 摩拜前端团队会收集每周前端优秀文章,每周五发布至掘金平台,欢迎关注我们~ 过个没什么了不起的一天,耀眼一些,你有资格 Top 榜 「中高级前端」...

    lykops 评论0 收藏0
  • 前端必懂之熟悉陌生BFC

    写在最前:BFC看起来是个很陌生的概念但它却时时发生在我们工作中,如何清除浮动影响?如何避免margin穿透问题?如何编写两栏自适应布局?都和BFC有这密不可分的关系,下面走进切图妞的世界,分分钟搞定BFC! 一、什么是BFC? BFC概念 块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素...

    Dongjie_Liu 评论0 收藏0
  • 前端必懂之熟悉陌生BFC

    写在最前:BFC看起来是个很陌生的概念但它却时时发生在我们工作中,如何清除浮动影响?如何避免margin穿透问题?如何编写两栏自适应布局?都和BFC有这密不可分的关系,下面走进切图妞的世界,分分钟搞定BFC! 一、什么是BFC? BFC概念 块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素...

    philadelphia 评论0 收藏0
  • 前端必懂之熟悉陌生BFC

    写在最前:BFC看起来是个很陌生的概念但它却时时发生在我们工作中,如何清除浮动影响?如何避免margin穿透问题?如何编写两栏自适应布局?都和BFC有这密不可分的关系,下面走进切图妞的世界,分分钟搞定BFC! 一、什么是BFC? BFC概念 块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视化CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素...

    includecmath 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<