拜托!不要再问我Session与Cookie的区别了

从我刚开始学程序时这一题就常出如今面试考题里,一直到如今都仍是能看见这个问题。ios

这个问题重要吗?我以为蛮重要的。由于 Session 所表明的是「状态」,若是没有了状态,一大堆功能都会失效。面试

对于工程师来讲必须去理解什么是 Session,以及如何操做它,而 Cookie 就是这之中很重要的一环。redis

所以这会是一系列的文章,我称之为 Session 与 Cookie 三部曲,会由浅入深,从不一样的面向去看 Session 与 Cookie。算法

这是系列文的第一篇,想用简单白话的方式通俗地跟你们解释什么是 Session,什么又是 Cookie,目标是但愿没有任何技术背景的人也可以看懂。数据库

要向没有技术背景的人讲这种概念性的东西,用一堆专有名词绝对是最差劲的作法。浏览器

而最好的作法一般是举一个现实生活中很贴近的例子,藉由这种方式比较能让毫无技术背景的读者们去理解这究竟是个什么东西。服务器

所以,咱们从经营杂货店开始吧!微信

小明の杂货店cookie

四十岁的退休之后在家闲得发慌,每一天都过得毫无目标并且浑浑噩噩。网络

「退休之后不是应该无忧无虑吗?」小明也是这样问本身的,但没办法,他深知本身的个性就是这样,没办法闲下来,必定要作点事情才行。

因而,小明就用了退休金在家里附近的巷口开了间杂货店,而且取名为:「小明の杂货店」,是个毫无创意的名称,但把本身的名字放在招牌上一直是他的梦想。

小明平时人缘还算不错,在倒垃圾时会与旁边的婆婆妈妈闲聊,说着那个谁谁谁的儿子考上了台大,谁谁谁的女儿最近交了个男朋友,成为左邻右舍八卦网络的一部分。

不仅婆婆妈妈,连年轻的那一代也对他感受不错,八成是由于他很识相地不会硬要跟年轻人尬聊,看到他们都只是简单点个头示意一下,而不是像其余人劈头就把私事全都问了一遍。

所以在开幕那天,杂货店比如 Apple Store 开幕通常(除了没有人特意前一天就跑来排队之外),周遭的邻居们都跑来捧场,把整个店挤得风雨不透,单日营收甚至上百万(台币)。

第一天就能有如此成績,可见人缘是多么重要的一件事。有人缘,有人潮;有人潮,有钱潮。

但开幕毕竟是开幕,一般都是一家商店这辈子的巅峰,除非有跳楼大拍卖(假的那种不算,例如说天天都在大拍卖的)或是周年庆,否则都很难超越了。

随着日历一张张被撕开,店里的生意慢慢恢复正常,仍是喜欢传统便利商店的都跑回去便利商店了,而嫌远懒得走这么多路的则选择杂货店消费。

看似步上正轨的杂货店,问题却随着时间慢慢浮上台面。

脸盲症的困扰

小明身为杂货店的店长兼惟一的店员,全部大小事都是他一我的在处理。传统杂货店跟便利商店最大的差异在哪里?在于人情味。

就像是你去菜市场买菜的时候会被说帅哥或美女,或者是去买早餐的时候老板会问你:「同样?」,你只要点个头就好了。这些人与人之间的情感是不管信息怎么发展都没法取代的。

但是小明没有办法,由于他根本记不起来是同一我的。

每个来店里的人对小明来讲都是一个独立的个体,是彻底不相干的。你可能会疑惑说:「就算认不出脸,认声音、衣服、气味也均可以吧?」,看来你是过低估小明了。

小明不仅认不出脸,他什么都认不出来。我也不知道小明到底哪里出了差错,小明本身也不知道。

但总之就是这样,就算你天天来,天天穿着同样的衣服,用着同样的声音,他都认不出来你是同一我的。

讲一个例子你就知道了,有一次有个顾客结完账之后把发票忘在柜台,一出店门口才想起来,就马上跑回去拿。

结果小明彻底没认出来是同一我的,还觉得这人是想来偷拿发票的,跟他确认过买的品项一致之后才愿意把发票还给他。

对,就是这么夸张,小明每一次结帐都是在帮一个全新的人结帐。

在生活上或许没什么问题,反正小明无依无靠也没朋友,本身一我的生活惯了,但是在经营杂货店上面就有很大的问题了。

除了会让人以为很没有人情味之外,最大的问题就是有些顾客的需求他没办法处理。

有些人逛杂货店喜欢慢慢挑慢慢选嘛,而后有些物品可能又很重,或者是在结帐的时候才忽然想起来还要买什么,这时候就会把东西先放在收银台那里,本身跑回去拿其余品项。

我前面已经提过了,小明认人的能力是零,当客人拿新的物品回去收银台的时候,小明已经认不出他来了。

所以他不知道收银台上面那些物品是谁的,客人也很难跟小明证实说:「对,这些是我刚刚想买的」。

这个使用者体验简直差到不行,所以店里的生意每况愈下,只有那种果断型顾客会来消费(一进杂货店就往本身的目标走,拿完以后马上结帐的那种)。

小明固然注意到了这个情况,也知道不能再这样下去了,继续这样的话大概不用两个月店就会倒了。因而小明冥思苦想,快思慢想,东想西想,终于想到了一个解决方法。

方法虽老旧但有用

前面有提到太小明最大的问题是「每一个客人都是新的客人」,他没办法认出他们是同一个客人,因此天然也没法记住他们的「状态」,而这个才是最大的问题。

山不转路转,路不转头转,既然小明本身没办法记住状态,写张纸条不就得了吗?

当你在收银台结帐的时候写一张纸条给你,上面写着:「五香乖乖x一、义美鲜奶茶x1」,而后你就能够回去挑其余你想要的东西,当你再回来收银台的时候把这张纸条给小明,小明就知道这些东西是你的。

或者你是个常客,每次来都买同样的东西,小明就在结帐时写给你一张纸条,把你常买的东西全都写上去,这样下次结帐时你只要带那一张纸条过来,小明就知道你常买什么了!

你有看过那种凄美爱情电影吗?男女主角其中一方得了罕见疾病,天天都会完全失忆一次,另外一方就会在家里帮他写满便条纸,透过那些便条纸,主角才能知道本身是谁、对方是谁,以及本身到底发生了什么事。

对,你能够把小明想象成就是失忆的那个,而便条纸就是给客人的纸条。既然本身记不住,就让这些纸条代劳,把状态放在上面。

虽说客人要把纸条留着其实蛮不方便的,但前面说太小明人缘其实不错,所以常客都会看在他的面子上把纸条带着,让这个机制得以继续运做。而小明店里的生意也所以好转一点点。

对,只有一点点而已,由于随身携带一张纸条实在是太麻烦了,因此也没多少人会这样作。

再继续往下讲以前,咱们先进入中场休息。

中场休息

让咱们先从比喻回到网络世界里,HTTP 是无状态的,因此每个 Request 都是不相关的,就像是对小明来讲每一位客人都是新的客人同样,他根本不知道谁是谁。

既然你没办法把他们关联,就表明状态这件事情也不存在。

把左边换成顾客,右边换成小明也依然成立。多一个得是我多打了,但我懒得修。

那怎么办呢?在故事里咱们用纸条来解决这件事情,小明会在结帐时写下纸条并递给客人,客人下次只要再带着纸条过来,小明就知道发生什么事了。

小纸条功不可没

小明最大的问题就是他本身没办法记忆「状态」,所以须要倚靠一个机制来帮他管理「状态」,而这个机制咱们就叫作 Session。

本来对小明来讲,每个客人都是新的客人,彼此之间毫无关联,因此也没有任何状态可言。

但有了纸条之后,两个在小明眼中彻底不一样的客人被关联了起来,小明就能够知道:「原来这个新的客人是之前那个来买木材的客人!」

因此 Session 是什么?就是一种让 Request 变成 Stateful 的机制。以小明的例子来讲,Session 就是一种让客人之间能互相关联起来的机制。

小明靠纸条来实做 Session 机制,那在网络世界中能够靠什么呢?举一个最简单的例子,网址!

让咱们假设有个购物网站的网址是:market.tw,当你把苹果加入购物车的时候,你实际上是送一个 Request 给服务器,而后服务器会把你导到 market.tw?

item1=apple,接着你再把火山硅肺病加入购物车,网址就会变成:market.tw?item1=apple&item2=pneumonoultramicroscopicsilicovolcanoconiosis

最后你按下结帐,服务器就靠着你地址栏上的信息来判断你的状态是什么,在这个例子中就等同于看你的购物车里面有什么。

简单来讲呢,地址栏上的信息就是小明故事中的纸条,是储存状态的地方。而上述例子 Client 与 Server透过地址栏上的状态来实做 Session 机制。

好,中场休息差很少到这边要结束了。这一段是想先拉回网络的部分,从本来故事中的比喻切回真实世界网络的运做模式,以及先让你们理解 Session 究竟是个什么东西。

在接下来的故事里面,小明会碰到更多更多的问题,他能迎刃而解吗?让咱们继续看下去。

到底谁会随身携带纸条?

前面已经有提过了,尽管小明靠着这个纸条的机制留住了一些常客,可是新客人呢?有多少人会愿意为了再来这间店而特意留下具备状态的纸条?

基本上没有,由于这样子太麻烦了!

有天小明在快要入眠时,忽有一庞然大物拔山倒树而来,盖一灵感也。他想到了一个绝妙的 idea:「不会有人随身携带纸条,但总会随身携带手机吧!」

因而流程就变成这样子:

  • 客人来店里消费,小明结帐时请他拿出手机,并在手机里面留了一些信息
  • 客人第二次来店里,小明看看手机里有没有以前本身留下的信息

先不用管到底小明把信息放在手机的哪里,这不是重点;重点是手机里的信息取代了之前的纸条,客人不用刻意再带一个没有用的纸条了,只须要把原本就会随身携带的手机拿出来就好,跟之前相比方便许多。

好,接下来咱们终于要讲到标题的第二个东西了:Cookie。Cookie 是什么?Cookie 就是故事里面存在手机的信息。

想要知道真正使用 Cookie 的流程,你只要把上面的客人用「浏览器」来取代,小明用「服务器」来取代,就是答案了:

  • 浏览器发送一个 Request 给 Server,Server 叫浏览器设置 Cookie,浏览器便把这些数据存在 Cookie 里面。
  • 浏览器带着 Cookie 一块儿发 Request 给 Server,Server 根据 Cookie 的内容决定状态。

此次没有买火山硅肺病了

虽然在现实生活中不是每一个人都会随身携带手机,可是每一个浏览器都会把 Cookie 一并带上去,也会按照 Server 的指令来储存 Cookie。

你能够把 Cookie 称做是一个机制,Server 能够利用 Set-Cookie 这个语法让浏览器储存一些内容,而这些内容会在浏览器发送 Request 时一并送上来。

而浏览器里储存的那些内容也叫作 Cookie,就是咱们故事中所提的小纸条或者是存在手机里的信息。

前面有提过 Session 机制能够只靠地址栏操做,跟 Cookie 能够一点关系都没有。

但在实际应用上,Session 之因此经常跟 Cookie 绑在一块儿,就是由于靠 Cookie 来操做 Session 机制的话很是方便。

或者应该这样说,Cookie 原本就是为了操做 Session 而生的。藉由标准化的规范,制定了一个专门用来让浏览器与 Server 交换数据的机制。

若是用故事来比喻,就比如政府制定说每一个人随身必定要携带手机,而后手机里面必定要存小明留下来的状态。

这边再来作个简单的总结:

Session 是什么?就是一种让 Request 变成 Stateful 的机制。以小明的例子来讲,Session 就是一种让客人之间能互相关联起来的机制。在故事里面咱们用了纸条跟手机里的信息来比喻,有多种方式能够达成 Session。

在网络世界中,也有不少种方式能够来操做 Session,前面介绍过第一种是地址栏,第二种就是靠 Cookie。而 Cookie 就是存在浏览器里的一些信息。

讲到这边,差很少就把 Session 与 Cookie 的定义与介绍讲完了,但故事还没完呢,咱们还有最后一个问题要来解决。

咖啡寄杯的烦恼

虽然店里生意还能够,但小明无时无刻不想着怎么样发大财赚大钱,让店里的生意变得更好。

他观察到最近好多便利商店开始卖起了咖啡,并且时不时就买一送一或是第二件半价,而且贴心地提供了寄杯的服务。

寄杯就是指说你今天先喝一杯,剩下那杯我帮你记着,你下次来的时候跟我讲我再给你。

若是不提供这种服务,那买一送一就必定要两我的才能喝了(或是你马上喝两杯),根本就是排挤像小明这样的边缘人。秉持着将心比心的原则,小明固然是但愿提供寄杯服务的。

那该怎么寄呢?照以前那样不就得了吗?本来客人的手机里面会存着消费习惯之类的东西,如今多存一个还有几杯咖啡不就好了?

例如说客人买两杯只喝一杯,就在上面写着:coffee=1,表明还剩一杯咖啡,下次来的时候只要出示这个信息,就再给他一杯。

听起来十分合理,并且小明也这样作了,店里的生意变得更好,买咖啡的人越来越多,靠着咖啡就让单月营收翻了两倍。

一切看似很是顺利,直到小明月底对账的时候:不对啊,为何买咖啡的数量只有 55 杯,卖出去的却有 66 杯?

一贯很相信人的小明,在那一瞬间见识到了人心的险恶之处。没错,有人本身偷改信息,例如说把 coffee=1 加个几划改为 coffee=7,就得到了额外六杯的免费咖啡。

这些奥步让小明狠狠一晚上之间变成了大人,绝望的小明把悲愤转化成力量,只花了三个晚上就想到了两个解决方法。

第一个方法最简单,就是只要把存在客人手机上的信息加密就行了。

例如说本来是 coffee=1,通过小明自制的特殊加密算法以后,会变成 ED85B89167A84B631C10B046B5FB7FC0 这串只有小明知道怎么解开的密文。

这样一来,除非客人能够破解这段密码,不然信息就不可能被窜改。但有一个小缺点,那就是当小明想存的信息越来越多以后,这一串字也会越来越长,就会在客人的手机里面占更大的容量。

这个容量是有上限的,客人不会把整台手机都给你存这些信息,因此这点要特别注意。

这个方法解决问题的思路是这样的:「既然存在手机上的信息会被窜改,那我让他不能改就好」。

而第二个方法解决问题的思路是这样的:「既然存在手机上的信息会被窜改,那我把信息存在我这边不就行了吗?」

与其把那些消费习惯或是寄杯数量存在客人的手机里,不如把这些东西记在个人笔记本里面,而且用一种方式把这两个信息对应起来,这样就不怕数据会被改动了。

举例来讲,小明能够在笔记本写下客人的身份证字号跟相关资讯,例如说:「A111111111 coffee=1」,接着小明只在客人的手机里面存「A111111111」。

下次客人再来消费的时候,就透过身份证字号去笔记本里面查,就知道客人到底还剩几杯咖啡了。

因为小明的笔记本天天下班都会锁在保险箱里面,所以不用惧怕被偷或是被改,能够假设它必定是准确的。

而这样子的方式不把主要信息存在客人那里,而是存在本身这里,因此也不会有被窜改的风险。

但是有个问题,若是有人把身份证字号改为其余人的怎么办?那不就破功了吗?就能够伪造其余人的身份。

这个简单,不如不要用身份证字号,用一个 16 位数的英数字混合乱码好了,例如说:A59Uhe7I94J330mN,这样就很难被猜到了吧!

因而流程会变成这样:

客人那编只须要报 ID 便可,其余资讯都在小明那里

跟以前同样,他们都是透过一张纸条或者是手机里的信息来沟通,但惟一的差异是客人跟小明之间只透过 A59Uhe7I94J330mN 这个存在手机里的 ID 来验证身份,其余相关资讯都写在小明的笔记本里面。

这种验证的方法就像是我曾经去过的网咖。由于会员打咖比较便宜嘛,一小 60 变成一小 36,不办白不办,就办了一张会员卡。店员特别说明认卡不认人,必定要出示卡片才行。

我只要去打咖的时候出示这张会员卡,店员就知道我曾经消费过多少钱,也知道我喜欢点的餐点,全部的信息都是存在他们的系统里面,而个人身份就是透过这张会员卡来表示。

寄杯的例子中,会员卡就是 A59Uhe7I94J330mN 这个 ID,网咖的电脑系统就是小明的笔记本。

小明最后决定用第二种方法,也就是这种靠 ID 认人的方式来管理客人的状态。

今后以后就没有客人可以窜改信息了,而寄杯服务也运行的十分顺利,真是皆大欢喜,可喜可贺。

至于后来变得生意太好,让小明开了分店之后碰到的那些问题,就又是另一段故事了。

储存状态的方式

小明的故事说完了,该来把上面这一段变成网络的实际案例了。其实在网络世界中问题也是同样的。

前面已经提到过咱们会把状态存在 Cookie 里面,让 Request 之间可以变得有关联。

假设咱们今天要来作一个会员系统,那我要怎么知道这个 Request 表明的是哪个会员?

最直觉的方式就是登入之后把会员账号存在 Cookie 里面嘛,这样不就知道是谁了吗?

但是会碰到的问题就跟寄杯的故事同样,Cookie 里的东西是能够被窜改的,若是我改为了别人的会员账号,我就能够伪造他的身份登入了!

解决方法跟上面寄杯的解法同样:

第一个解法就是把 Cookie 里面的内容给加密,这样就没法被窜改了。这种方式就称之为 Cookie-based session,意思就是你把全部的 Session 状态都存在 Cookie 里面。

因此不要把「用 Cookie 来操做 Session 机制」跟「Cookie-based session」搞混了,二者是不同的。

至于缺点的话前面有提到,Cookie 的大小是有限制的,超过大小的话浏览器就不帮你存了。

所以当你想存的信息愈来愈多,Cookie 固然也愈来愈大,就有可能超过这个限制。

或者是哪天你的加密方式以及密钥被黑客破解,那黑客同样能够伪造任何人的身份。

第二个解法就是透过一个 ID 来辨识身份,这个 ID 称之为 Session Identifier,简称 Session ID。

Server 只在 Cookie 里面存一个 Session ID,其他的状态都存在 Server 那边,我习惯把 Server 那边的数据称为 Session Data:

其实就是小明笔记本的翻版而已

Session ID 的产生方式跟前面说的同样,一般会是一个没法猜想的随机数。

你可能会想说:「很难猜是一回事,但机率不是 0 啊!」,对,的确是有机率可以猜到,可是那个机率过低过低了(例如说几千亿分之一之类的)。

并且 Server 在你乱猜猜错几回以后就有可能把你 ban 掉不让你继续猜,因此没什么问题。

不过这边要特别注意的一点是 Session ID 基本上是种认证不认人的方式,也就是说一旦你的 Session ID 被偷走,别人就能够伪造你的身份来登陆了。而这个 Session ID 一般都是保存在 Cookie 之中。

这就是为何有些网站发生骇客入侵的情形以后你会忽然被注销,由于黑客可能偷到一批 Session ID,这时候服务器就会把全部 Session 数据所有清空。

以故事来比喻就是把笔记本丢掉,买一本新的,这样被偷走的那些 Session ID 就没用了,而 Server 找不到你的 Session ID,天然就没法登入,所以把你给注销了。

网站发生问题时客服会要你先把 Cookie 清掉也是相似的道理,由于 Cookie 跟状态有关,有时候可能程序有一些 Bug,把你导到了错误的状态,把 Cookie 清空等于把状态清空,从新再开始,就有可能变得正常。

总结

其实我本来觉得我很懂 Cookie 跟 Session,但越研究愈加现好像不是这么一回事,只是我自我感受良好而已。

但把该看的数据都看完一遍以后,再让本身沉淀个几天,大体上就能彻底理解整个脉络的发展。

Session 是什么?就是一种让 Request 变成 Stateful 的机制。以小明的例子来讲,Session 就是一种让客人之间能互相关联起来的机制。

在故事里面咱们用了纸条跟手机里的信息来比喻,有多种方式能够达成 Session。

在网络世界中,也有不少种方式能够来实做 Session,前面介绍过第一种是地址栏,第二种就是靠 Cookie,而 Cookie 就是存在浏览器里的一些信息。

常见的错误认知是必定要有 Cookie 才能实做 Session,这是错误的。

有了 Session 以后,会碰到数据被窜改的问题,这时候有两种解决方式:

  • 一个是 Cookie-based session,意思是你照旧把状态存在 Cookie,可是加密之后再存。
  • 另外一个方法是把状态存在 Server 端,靠一个 Session ID 来辨识,这个状态你能够存成档案,能够存在內存里,也能够存在数据库,只是实做方式的不一样而已,但原理都是同样的。

而这个状态储存的地方在口语上也会被称之为「Session」,例如说:「帮我把 user id 存在 Session 里」,或者是「注销记得把 Session 清空」之类的。

因此在实际用法中,我认为 Session 之因此很差理解是由于太多地方用到同一个词,但倒是在指代不一样的东西(但是又很相似)。跟 API 有点像,太多地方都用到这个词了。

做者:胡立
出处:https://medium.com/@hulitw/se...

关注 民工哥技术之路 微信公众号对话框回复关键字:1024 能够获取一份最新整理的技术干货:包括系统运维、数据库、redis、MogoDB、电子书、Java基础课程、Java实战项目、架构师综合教程、架构师实战项目、大数据、Docker容器、ELK Stack、机器学习、BAT面试精讲视频等。

相关文章
相关标签/搜索