express中cookie的使用和cookie-parser的解读

最近在研究express,学着使用cookie,开始不会用,就百度了一下,没有百度到特别完整的解答。查阅了express的API,综合了网友的博客,解读了cookie-parser的源码,以及使用WebStorm和Chrome验证,终于明白了express中cookie的使用。顾此篇文章即是分享也是总结。

1. cookie的创建

express直接提供了api,只需要在需要使用的地方调用如下api即可


    function(req, res, next){
        ...
        res.cookie(name, value [, options]);
        ...
    }

express就会将其填入Response Header中的Set-Cookie,达到在浏览器中设置cookie的作用。

  • name: 类型为String

  • value: 类型为String和Object,如果是Object会在cookie.serialize()之前自动调用JSON.stringify对其进行处理

  • Option: 类型为对象,可使用的属性如下

       domain:cookie在什么域名下有效,类型为String,。默认为网站域名
       expires: cookie过期时间,类型为Date。如果没有设置或者设置为0,那么该cookie只在这个这个session有效,即关闭浏览器后,这个cookie会被浏览器删除。
       httpOnly: 只能被web server访问,类型Boolean。
       maxAge: 实现expires的功能,设置cookie过期的时间,类型为String,指明从现在开始,多少毫秒以后,cookie到期。
       path: cookie在什么路径下有效,默认为'/',类型为String
       secure:只能被HTTPS使用,类型Boolean,默认为false
       signed:使用签名,类型Boolean,默认为false。`express会使用req.secret来完成签名,需要cookie-parser配合使用`
       

    上面是我结合实验和自己的理解,对官网api的翻译。原英文如下:

图片描述

用例如下

res.cookie('name', 'koby', { domain: '.example.com', path: '/admin', secure: true });
//cookie的有效期为900000ms
res.cookie('rememberme', '1', { expires: new Date(Date.now() + 900000), httpOnly: true });
//cookie的有效期为900000ms
res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true });

//cookie的value为对象
res.cookie('cart', { items: [1,2,3] });
res.cookie('cart', { items: [1,2,3] }, { maxAge: 900000 });

res.cookie('name', 'tobi', { signed: true });

2.cookie的删除
express直接提供了api删除浏览器中的cookie,只需要在需要使用的地方调用如下api即可


    function(req, res, next){
        ...
        res.clearCookie(name [, options]);
        ...
    }

3.利用cookie-parser读取cookie
cookie-parser是一个非常好用方便的插件,可以直接用在express和connect中,官文地址为https://www.npmjs.com/package/cookie-parser。npm安装命令

$npm install cookie-parser --save

使用方式

var express = require('express');
var cookieParser = require('cookie-parser');

var app = express();
//不使用签名
app.use(cookiePareser());

//若需要使用签名,需要指定一个secret,字符串,否者会报错
app.use(cookiePareser('Simon'));
  • 如果没有为signed功能,cookie-parser通过如下代码解析req.headers.cookie

        //index.js
        var cookie = require('cookie');
        var parse = require('./lib/parse');
        
        if (req.cookies) return next();    //如果存在req.cookies跳过这个middleware
        var cookies = req.headers.cookie;    //保存对象地址,提高运行效率
        req.cookies = Object.create(null);    //创建一个对象,解析后的且未使用签名的cookie保存在req.cookies中
        req.cookies = cookie.parse(cookies);    //与express中调用cookie.serialize()对应,解析cookie
        req.cookies = JSONCookies(req.cookies);    // JSON字符序列转化为JSON对象
        //./lib/parse.js
        
        //接续cookie中的JSON字符序列
        exports.JSONCookies = function(obj){
          var cookies = Object.keys(obj);    //获取obj对象的property
          var key;
          var val;
        
           //循环判断并解析
          for (var i = 0; i < cookies.length; i++) {
            key = cookies[i];
            val = exports.JSONCookie(obj[key]);
        
            //如果是JSON字符序列则保存
            if (val) {
              obj[key] = val;
            }
          }
        
          return obj;
        };
        
       //解析JSON字符序列
        exports.JSONCookie = function(str) {
          if (!str || str.substr(0, 2) !== 'j:') return; //判断是否为JSON字符序列,如果不是返回undefined
        
          try {
            return JSON.parse(str.slice(2));    //解析JSON字符序列
          } catch (err) {
            // no op
          }
        };
  • 如果使用了signed功能,cookie-parser通过如下代码解析req.headers.cookie

        //index.js
        var cookie = require('cookie');
        var parse = require('./lib/parse');
        
        if (req.cookies) return next(); //如果存在req.cookies跳过这个middleware
        
        //调用res.cookie(name, value , {singed: true}),express会使用req.secret。故使用了签名功能,需给cookie-parser传递secret,且res.cookie(name, value , {singed: true})需在cookie-parser插        
        //入express后再使用
        req.secret = secret;     
        req.cookies = Object.create(null);
        req.signedCookies = Object.create(null); //创建req.singedCookies,所有解析后的signed cookie都保存在这个对象中,req.cookies中没有任何signed cookie
    
        // 如果请求中没有cookies
        if (!cookies) {
          return next();
        }
    
        req.cookies = cookie.parse(cookies, options); //与express中调用cookie.serialize()对应,解析cookie
    
        // parse signed cookies
        if (secret) {
          //判断是否为singed cookie。如果是,则去掉签名,同时删除req.cookies中对应的property,将这些去掉签名的cookie组成一个对象,保存在req.signedCookies中
          req.signedCookies = parse.signedCookies(req.cookies, secret); 
          // JSON字符序列转化为JSON对象
          req.signedCookies = parse.JSONCookies(req.signedCookies);    
        }
    //./lib/parse.js
    var signature = require('cookie-signature');

    exports.signedCookies = function(obj, secret){
      var cookies = Object.keys(obj);    //获取obj对象的property
      var dec;
      var key;
      var ret = Object.create(null);  //创建返回对象
      var val;
    
      for (var i = 0; i < cookies.length; i++) {
        key = cookies[i];
        val = obj[key];
        dec = exports.signedCookie(val, secret);
    
        //判断是否是去掉签名后的value,如果是保存该值到ret中同时删除obj中的相应property
        if (val !== dec) {
          ret[key] = dec;
          delete obj[key];
        }
      }
    
      return ret;
    };

    exports.signedCookie = function(str, secret){
        //判断是否添加了签名,如果添加了签名则去掉签名,否则返回原字符串
      return str.substr(0, 2) === 's:' 
        ? signature.unsign(str.slice(2), secret)
        : str;
    };

综上所诉,解析后的unsigned cookie保存在req.cookies中,而解析后的signed cookie只保存在req.signedCookies中。使用cookie-parser插件,后续代码直接使用req.cookies或者req.signedCookies即可


仰望星空
喜欢技术,乱七八糟地懂一些
105 声望
2 粉丝
0 条评论
推荐阅读
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs39阅读 4.7k评论 5

封面图
安全地在前后端之间传输数据 - 「3」真的安全吗?
在「2」注册和登录示例中,我们通过非对称加密算法实现了浏览器和 Web 服务器之间的安全传输。看起来一切都很美好,但是危险就在哪里,有些人发现了,有些人嗅到了,更多人却浑然不知。就像是给门上了把好锁,还...

边城31阅读 7.1k评论 5

封面图
涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco20阅读 2k评论 2

在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 1.9k

封面图
【已结束】SegmentFault 思否写作挑战赛!
SegmentFault 思否写作挑战赛 是思否社区新上线的系列社区活动在 2 月 8 日 正式面向社区所有用户开启;挑战赛中包含多个可供作者选择的热门技术方向,根据挑战难度分为多个等级,快来参与挑战,向更好的自己前进!

SegmentFault思否20阅读 5.6k评论 10

封面图
过滤/筛选树节点
又是树,是我跟树杠上了吗?—— 不,是树的问题太多了!🔗 相关文章推荐:使用递归遍历并转换树形数据(以 TypeScript 为例)从列表生成树 (JavaScript/TypeScript) 过滤和筛选是一个意思,都是 filter。对于列表来...

边城18阅读 7.6k评论 3

封面图
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...

原谅我一生不羁放歌搞文艺14阅读 19.8k评论 9

105 声望
2 粉丝
宣传栏