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

262dc00a82ab541d5f21fccfb3cbb697.gif

作者 | 零一

来源 | 前端印象

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

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

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

1b8d3a8ddb69bf0112be0e369c7c3a24.png

这肯定不合适!

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

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

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

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

  • connect-redis

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

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

21a7dc5bbd0b704a96e190db4f97336d.png

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

5278e44e7d1da17a0ba931c12816ecac.gif

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

0559169c8380b32846c193fd27792969.png

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

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

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

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

aaf9b27697713de3a23a59ec986a654e.png

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

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

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

b0b370e6d6e038befb21c15f9be30702.png

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

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

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

没办法了,继续从头 debug 吧

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

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

1ff113e83e25df019646d8063d140266.png

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

0003e345f937a60174d8b651d27cef1f.png

看了大致的逻辑,发现 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 函数没有被调用导致的了

7a72dc0dd753583584ff5adb4eb76fb9.png

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

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

20ecca98eb5094227352c22a2c1f5832.png

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

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

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

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

3fceecc217c32d5e1a33db07da6bacbd.png

还记得这个图么?这是我一开始准备用这些库时看的,但我没看到这个信息:当 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 的,它们的关系是这样的:

3463447986fe812782d636e2b53dcab5.png

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

8d3ec7745c0b28a1a302181016ba33df.png

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

结论

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

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

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

77252ef22ac7694a273f1f60d5346ced.gif

往期推荐

如果让你来设计网络

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

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

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

c13e6247cce5504351c2fdc1e6ac5f0c.gif

点分享

6e6d45b4e57973ecc96691aa54672009.gif

点收藏

acd724697c19327a515130041cc7c9a7.gif

点点赞

deb6ac45bb6a669936d37c77b71761e2.gif

点在看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/512038.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一种命令行解析的新思路(Go 语言描述)

简介: 本文通过打破大家对命令行的固有印象,对命令行的概念解构后重新梳理,开发出一种功能强大但使用极为简单的命令行解析方法。这种方法支持任意多的子命令,支持可选和必选参数,对可选参数可提供默认值,支…

云原生 DevOps,模型化应用交付能力很重要

简介: DevOps 文化及其支撑其落地实践的自动化工具与平台能力在云原生架构渐为普及的背后,发挥了关键的价值。 撰稿:溪洋 云原生正在成为企业业务创新和解决规模化挑战的加速器。 云原生带来的变革绝不限于基础设施和应用架构等技术层面&a…

如何在 Kubernetes Pod 内进行网络抓包

作者 | Addo Zhang来源 | 云原生指北使用 Kubernetes 时,经常会遇到一些棘手的网络问题需要对 Pod 内的流量进行抓包分析。然而所使用的镜像一般不会带有 tcpdump 命令,过去常用的做法简单直接暴力:登录到节点所在节点,使用 root …

EDAS 4.0 助力企业一站式实现微服务架构转型与 K8s 容器化升级

简介: EDAS 正式来到 4.0 时代,发布多项重磅新能力;同时联合新产品—云原生应用设计开发平台 ADD 1.0,一起发布云原生应用研发&运维 PaaS 产品家族,助力企业应用架构现代化升级。 作者:安绍飞 前言 …

如何用20分钟就能获得同款企业级全链路灰度能力?

简介: MSE 微服务引擎将推出服务治理专业版,提供开箱即用且完整专业的微服务治理解决方案,帮助企业更好地实现微服务治理能力。如果您的系统也可以像本文描述的那样,快速具备完整的全链路灰度能力,并基于该能力进行进一…

云桌面场景化升级新作,锐捷网络发布全新远程办公“U空间”

编辑 | 宋慧 出品 | CSDN云计算 远程办公真的来了。 在硅谷的科技公司远程办公常态化之后,国内的科技大厂也在跟进中,如携程正式宣布的32混合办公模式。根据iiMedia Research艾媒咨询数据显示,在2020年新春期间,中国远程办公人员…

细说双 11 直播背后的压测保障技术

简介: 阿里云 PTS 站在双 11 巨人的肩膀上,是阿里全链路压测的延伸。PTS 通过伸缩弹性,轻松发起用户百万级别的流量,免去机器、人力成本;PTS 对流量的控制,能够实时脉冲,精准控制; 是…

【SpringCloud-Alibaba系列教程】14.一文教你入门RocketMQ

<本文已参与 RocketMQ Summit 优秀案例征文活动&#xff0c;点此了解详情> MQ简介 MQ(Message Queue)是一种跨进程的通信机制&#xff0c;用于消息传递。通俗点说&#xff0c;就是一个先进先出的数据结构。 MQ应用场景 异步解耦 很多场景不使用MQ会产生各个应用见紧密…

独家 | 2021双11背后的数据库硬核科技

简介&#xff1a; 今年双11&#xff0c;阿里云数据库技术有什么不一样&#xff1f; 2021年&#xff0c;是阿里巴巴首个100%云上双11 双11峰值计算成本 相比去年下降50% 作为全球规模最大的数字工程之一 双11无疑是对阿里技术人的“大考” 在又一次技术“严考"面前 …

前沿分享|阿里云资深技术专家 魏闯先:AnalyticDB PostgreSQL年度新版本发布

简介&#xff1a; 本篇内容为2021云栖大会-云原生数据仓库AnalyticDB技术与实践峰会分论坛中&#xff0c;阿里云资深技术专家 魏闯先关于“AnalyticDB PostgreSQL年度新版本发布”的分享。 本篇内容将通过三个部分来介绍AnalyticDB PG年度新版本发布。 一、AnalyticDB PG云原生…

Apache RocketMQ在我司的最佳实践--智慧政务场景下的分布式消息与分布式事务

<本文已参与 RocketMQ Summit 优秀案例征文活动&#xff0c;点此了解详情> 缘起 对于Apache RocketMQ的了解&#xff0c;追溯起来&#xff0c;可以说是从开源初始&#xff0c;就认识到了它。那时候的它&#xff0c;还是个幼年&#xff0c;没有成熟的社区&#xff0c;也…

前沿分享|阿里云数据库资深技术专家 姚奕玮:AnalyticDB MySQL离在线一体化技术揭秘

简介&#xff1a; 本篇内容为2021云栖大会-云原生数据仓库AnalyticDB技术与实践峰会分论坛中&#xff0c;阿里云数据库资深技术专家 姚奕玮关于“AnalyticDB MySQL离在线一体化技术揭秘”的分享。 本篇内容将通过三个部分来介绍AnalyticDB MySQL离在线一体化技术。 一、传统大…

今年双11,阿里业务100%上云

简介&#xff1a; 阿里巴巴业务的研发效率提升了20%、CPU资源利用率提升30%、应用100%云原生化、在线业务容器可达百万规模&#xff0c;同时计算效率大幅提升&#xff0c;双11整体计算成本三年下降30%。 今天&#xff0c;阿里巴巴首席技术官程立宣布——2021天猫双11是首个100…

linux unshare 命令,详解Linux Namespace之User

User namespace 是 Linux 3.8 新增的一种 namespace&#xff0c;用于隔离安全相关的资源&#xff0c;包括 user IDs and group IDs&#xff0c;keys, 和 capabilities。同样一个用户的 user ID 和 group ID 在不同的 user namespace 中可以不一样(与 PID nanespace 类似)。换句…

从更高到更好 2021阿里双11背后的技术亮点

简介&#xff1a; 今年&#xff0c;是阿里巴巴第13个双11。今年双11&#xff0c;阿里巴巴大促峰值的计算成本相比去年下降50%&#xff1b;截至11日&#xff0c;小蛮驴无人车在双11期间累计配送快递已超过100万件。更多的阿里自研技术投入到双11&#xff0c;在芯片、服务器等硬核…

博时基金基于RocketMQ的基金数字化陪伴体系的架构实践

简介&#xff1a; 本文以博时基金的金融场景为案例&#xff0c;阐述RocketMQ在提升客户陪伴效率和丰富金融场景化能力等方面的提升作用。 <本文已参与 RocketMQ Summit 优秀案例征文活动&#xff0c;点此了解详情> 基于RocketMQ的基金数字化陪伴体系的架构实践 博时基金…

面对DNS劫持,只能坐以待毙吗?

简介&#xff1a; 借助 ARMS-云拨测&#xff0c;我们可实时对网站进行监控&#xff0c;实现分钟级别的监控&#xff0c;及时发现 DNS 劫持以及页面篡改。 作者&#xff1a;白玙 DNS 劫持作为最常见的网络攻击方式&#xff0c;是每个站长或者运维团队最为头疼的事情。苦心经营…

linux写程序四则运算,Shell编程之变量及四则运算

Shell的学习目标Shell的基本语法结构&#xff1a; 如&#xff1a;变量的定义、条件判断、循环语句(for、until、while)、分支语句、函数和数组等。基本正则表达式的应用文件处理&#xff1a;grep、sed、awk工具的使用使用shell脚本完成复杂的任务&#xff1a;服务搭建、批量处理…

博时基金基于 RocketMQ 的互联网开放平台 Matrix 架构实践

简介&#xff1a; 随着近两年业绩的抢眼&#xff0c;公募基金迎来了乘风破浪式的发展&#xff0c;截至 2021 年 1 月底&#xff0c;资产管理规模已破 20 万亿&#xff0c;创下了历史新高。 ​ <本文已参与 RocketMQ Summit 优秀案例征文活动&#xff0c;点此了解详情> 作…

首次 统一调度系统规模化落地,全面支撑阿里巴巴双 11 全业务

简介&#xff1a; 今年双 11 首次规模化亮相的统一调度&#xff0c;通过一套调度协议、一套系统架构&#xff0c;统一管理底层的计算、存储、网络资源&#xff0c;超大规模、高效率、自动化的资源弹性&#xff0c;实现了业界新的突破。在离线混部、离在线混部、新的快上快下技术…