作者 | 零一

来源 | 前端印象

这两天在学习 node 相关的知识时,做出了一些错误的行为~

在做用户登录相关业务时涉及到了 cookie、session 的存取,一搜就找到了 express-session 这个中间件,真香!配几个配置就可以自动生成 cookiesessionId

express-session 对于 session 的存储默认是存在内存中的

这肯定不合适!

  • 项目一挂 或者 重启,session信息全丢了,所有用户都需要重新登录

  • 多个进程之间也无法共享 session 数据

然后去搜了下有没有 redis(key - value 形式的数据库) 相关的库,咔,又出来两个:

  • redis(github上叫 node-redis,npm上叫 redis

  • connect-redis

前者是提供了 js 可调用的操作 redis 数据库的底层方法;后者就是获取 redis 数据库实例,成为 express-session 存取 session 信息的载体

官网的使用说明也很清楚:

后来在我调试时发现出现了很多的问题,比如第一次调用 API(不携带cookie),接口迅速响应,并带回了 Set-cookies 头,但是! 我接口响应的数据呢???我明明返回了

最终 接口 15s 未返回,超时了

因为这个问题应该很明显了,接口是有响应返回的,但返回数据这块儿出了问题,先快速定位了问题所在,就是 express-sessionredisconnect-redis 这三个库其中一个有问题,因为在接入这几个库之前,session存储在内存中是能正常返回的

于是我就去这几个库的 issue 里搜了一下是否有类似的问题,毕竟都是这么多 star 的库,明显的问题肯定早就被人提出来了,然而!没有

我又开始在搜索引擎搜索,也同样没有!

怎么回事... 合着就我一个人有问题,难道说...?

我要发现一个惊天大bug,然后给他们提pr,从此人生一帆风顺了?(hhhhh,不知道大家有时候有没有这样的想法)

这就开始了我的 debug 看源码之路

于是我 "咔",在 express-session 里打了个断点,同时也给 redis 服务开启了 monitor 监控,调试时发现 redis 存取值的时候 key 竟然不一致

啥玩意儿?SET 的 key 是一段 hash + cookie的json字符串,value 是一个函数字符串(存个函数干啥?此时我非常非常疑惑);GET 的 key 却只是一小段 hash

我找到源码里存取key的位置打上了断点,发现存取值的key确实不一样,但又因为此时我还没看多少源码,所以对这块儿的逻辑我暂且表示赞同,因为可能这就是别人库的 feature 呢?

提前说明一下,最终发现破案也是因为这里,但当时的我是没法断定的

没办法了,继续从头 debug 吧

res.status(200).send({ name: '01' })

先是我接口函数里返回了 http 状态码 200(怪不得我的接口立马返回了200)

然后 send 函数调用走到了 end 函数中

看了大致的逻辑,发现 express-session 重写了 resend 函数,在里面判断 session 信息有无修改,进而判断需不需要保存 session 到 store 里

// 存储原始的 end 函数
var _end = res.end;
var _write = res.write;
var ended = false;
// 重写 end 函数
res.end = function end(chunk, encoding) {// 执行额外的逻辑// ...// 最终执行原始的 end 函数return _end.call(res, chunk, encoding);
};

既然 debug 都走到 end 里了,说明问题快出来了,能猜到可能是原始的 end 函数没有被调用导致的了

走到了调用 set 函数的地方,他第一个参数传了个数组,第二个参数传了个回调函数,该回调函数执行就会走到 原始 end 函数的调用,按道理来说就没问题了啊!

我继续下一步调试,发现根本没走到回调函数里,去查了一下 this.client.set 的 TS 类型

这次又证明了 redis 为什么 SET了key为一长串字符串,value为一个函数

this.client 是 redis 这个库提供的方法,我们是将 redis 生成的实例对象传给 express-session 作为 session 存储的载体,那现在看起来是 这两个库没互相兼容??

目前内心OS:两个这么大的库,更新了都不做互相兼容的么

于是我又跑回去看文档,gan!

还记得这个图么?这是我一开始准备用这些库时看的,但我没看到这个信息:当 redis 库为 v4 版本时,createClient 时需要加一个 legacyMode: true 的参数,开启传统模式?然后再回到我刚才发现的问题,这个参数是不是就是为了兼容 express-session 的?

于是我赶紧加上这个参数,嚯,真的好了!接口也迅速返回内容了

所以最终是 redis 做了版本升级,更改了 api 的使用方式

// 旧版 redis
client.set(key, value, cb)// 新版 redis
await client.set(key, value)

确实还是新版的api使用起来舒服,换作旧版的,大家使用前可能还需要封装一下

但是 express-session 并没有更改 set 函数调用的传参方式,这也很正常,毕竟这个库只是为了 session 管理用的,而 redis 以及各种 db 库又不止是专门服务于 express-session 的,它们的关系是这样的:

然而当 db 库进行了更新,就需要中间一层来连接了,也就是类似我们本文用到的 connect-redis,此时它们的关系是这样的

所以我们在用 connect-redis 时,传一个 legacyMode: true 参数就可以让 redis 兼容 express-session 的使用了

结论

该说啥呢,被自己蠢哭了,一开始不好好看文档,导致后面花了一天时间去排查问题,还被迫看了这么多源码,你要问我后悔吗?我又不后悔:被倒逼着去看了一个库的源码梳理了大致的逻辑学到了思想巩固了 cookie、session 的知识学会了 redis 库的调试和各种命令长了个教训(以后要好好看文档)

什么时候比较适合看源码呢?当然是有需要的时候,侬,比如我这次的经历

大家千万别学我一样,粗心大意,文档还是要好好看,这就跟以前上学的时候答题不仔细看题目一样,是大忌啊!!!

往期推荐

如果让你来设计网络

用过留痕,谁动了我的档案?

一把王者的时间,我就学会了Nginx

明明还有大量内存,为啥报错“无法分配内存”?

点分享

点收藏

点点赞

点在看

被自己的行为蠢哭了,意识到原因后真香!相关推荐

  1. python之没事别搞多版本!-----------当我知道原因,真的被自己蠢哭了

    事情的来龙去脉: 公司直接下发一个完整的接口自动化项目,要求可以用命令行的方式跑通代码.其他同事都能跑通,就我不行.pycharm报错如下: 脑瓜一洞:要不我百度看看吧! 百度关键词:usage: p ...

  2. 解决 unity 按住鼠标右键 WS不能前进后退(我被自己蠢哭了)

    今天学习的时候突然 在sence 按住鼠标右键 WS不能前进后退 搞了半天 无意间点到 IOS是正交模式 Persp这个是透视模式 近大远小再点一下 变成这样就可以用了 时间过去好多年了其原理 也很简 ...

  3. 蠢哭了,debug版本可用release版本出错

    记录一下本人遇到的问题,可能不适用于各位. win10 vs2015  MFC编写的一个动态库dll工程,debug版本release版本编译都通过.但是运行时debug版本可用 release版本出 ...

  4. 【蠢哭自己系列】Linux转到桌面目录下

    一.问题描述 可以看到在$HOME路径下有中文子路径和英文子路径,我们要是想要转到英文子路径直接使用以下命令即可,但是如果想要转到中文子路径就不能单纯改一下路径名称,而是要在子路径名称前加" ...

  5. 【虐到哭】 10家大厂面试真题

    大数据开发方向知识图谱,请点击下面的连接: <大数据方向学习面试知识图谱> 腾讯 关键词[Java基础][数据结构][操作系统][算法][数据库][缓存] 自我介绍 介绍一下你在项目中的承 ...

  6. 90后小学计算机课,看着看着就哭了,那些年我们90后的小学语文课本

    说起最近引起热议的北大学霸杀母案,闹得是沸沸扬扬.背后引发的思考,很多文章都提到了教育问题.在压抑的家庭里,孩子学会了伪装自己,有两副面孔.如果要不是杀母的事情被曝光,大家都还以为吴谢宇是一个完美的学 ...

  7. 安卓开发2年,入职字节跳动那天我哭了,被裁后奋战3个月终拿下

    前言 先说一下自己的个人情况,18届应届生,通过校招进入到了蘑菇街,然后一待就待了差不多2年多的时间,可惜的是今年4月份受疫情影响遇到了大裁员,而我也是其中一员.好在早有预感,提前做了准备,之前一直想 ...

  8. 2018福大软工实践第八次作业

    目录 团队信息 分工选择 课上分工 课下分工 ToDolist alpha版本要做的事情 燃尽图 UML 用例图 状态图 活动图 类图 部署图 实例图 对象图 时序图 包图 通信图 贡献分评定 课上贡 ...

  9. 福大软工1816 · 第八次作业课堂实践

    目录 团队信息 分工选择 课上分工 课下分工 ToDolist alpha版本要做的事情 燃尽图 UML 用例图 状态图 活动图 类图 部署图 实例图 对象图 时序图 包图 通信图 贡献分评定 课上贡 ...

最新文章

  1. 洛谷P2904 [USACO08MAR]跨河River Crossing 动态规划
  2. js 导出到excel
  3. 计算机辅助教学 林筑英,视频教学制作技巧.doc
  4. SAP Spartacus Product 明细页面 meta description 标签页的数据源
  5. mysql 测试与mongodb 测试对比
  6. jdbc事务和事务的隔离级别
  7. 计算机节电模式不能打开,电脑进入节电模式打不开怎么办
  8. Nvidia CUDA初级教程4 GPU体系架构概述
  9. java map 实例_java中map集合嵌套形式简单示例
  10. wordpress iis php,Windows IIS 上安装部署 WordPress 网站快速简要教程
  11. 16进制转浮点型_浮点型变量和BigDecimal的使用
  12. Java仓储物流项目_基于jsp的物流仓库管理系统-JavaEE实现物流仓库管理系统 - java项目源码...
  13. BarTender数据批量打印软件的入门操作
  14. HLW8032功率计+esp8266WiFi插座 mixly blynk
  15. 为什么要学统计学:赤裸裸的统计学
  16. 终端应用安全之网络流量分析
  17. react仿钉钉流程图-审批工作流
  18. 该战斗的时候战斗,该转身的时候转身,但请保持优雅
  19. 卸载并安装NVIDIA显卡驱动
  20. UE4虚幻引擎UI界面动画制作!

热门文章

  1. python输错了怎么办_python怎么实现输错三次密码之后锁定
  2. java对象底层原存储结构图解_图解图库JanusGraph系列-一文知晓“图数据“底层存储结构...
  3. vue组件一直注册不了_Vue自定义组件及组件的注册方法
  4. url存在宽字节跨站漏洞_5分钟速览丨常见的Web安全漏洞及测试方法
  5. 线性规划图解法求最优解_高中数学:简单的线性规划问题
  6. pycharm中python的默认安装路径_mac PyCharm添加Python解释器及添加package路径的方法...
  7. c# out关键字 vb_c# 关键字:ref 和 out
  8. visio图标_弱电间机柜原型图整理,可编辑!(Excel,visio,CAD)
  9. 【文末有福利】艺术创造规则,而不是规则创造艺术
  10. 2019诺贝尔化学奖: 二战老兵的传奇人生