/

什么是Session?Session是怎么实现的

该篇文章首发于boyn.top,转载请声明

什么是Cookie,什么是Session?

一言以蔽之,Cookie和Session都是为了保存用户在浏览器浏览时所产生的状态而进行持久化的值.

我们知道,HTTP协议是一个无状态的协议,每一次HTTP请求和响应都不会与上一个与下一个HTTP请求有关.但是有时候我们需要保存一些用户的信息以识别用户是否登录,登录的信息等等.这个时候,HTTP协议就无法满足我们了,所以我们需要一些手段来使HTTP的多个请求之间产生关联,而这个关联,就是Cookie和Session.

Cookie是放在HTTP头部中的一个或多个键值对,它有名称,内容,所在域名和声明路径,过期时间这几个属性.在我们请求的时候,浏览器会自动识别浏览的网页并将cookie自动填充放入头部中,这一操作对于用户来说的透明的,我们无需主动声明要保存什么Cookie和请求时带什么Cookie.

image-20200401114525430

Session

相比与Cookie保存在用户态,Session则是保存在服务端中,在这里需要读者朋友们理清楚,Session和Session的实现是分离的,Session只是一个抽象的概念,被提出来用于在服务端中保存用户的状态,但是其提出时并不限制实现的方法,我们在服务端中可以有各种各样的方式来保存Session,比如直接用一个Map,比如用分布式存储集群,比如用Redis,Memcached等等

Cookie和Session的不同

Cookie和Session有什么不同呢?这就要从HTTP的头部信息开始说起了.我们知道,一般一个HTTP的请求(以GET为例)头部大小是有限制的,我们不能放入非常大的信息在头部中,但是一个大型网站,对于用户状态的管理是十分复杂的,一般来说会涉及若干个Cookie,所以在Cookie保存所有的用户信息状态,即不安全,也不一定能够放得下.所以Cookie在大多数时候,只会保存一个Session ID,用于标记该Cookie对应服务端中的哪一个Session,在服务端进行请求的时候,可以解析传入的Cookie并索引到对应的Session信息供处理函数使用

Session是怎么实现的

成熟的Web开发框架一般都会有自己的Session实现.在下面我们就为大家来解析一下是怎么是实现Session的

我们以gorilla/sessions这个库为例,来分析Session是怎么进行存储的.在Session这个库中,提供了两种存储的方式:文件系统与Cookie存储.当然,Session信息的存储并没有一定要求在哪个地方,我们完全可以放在数据库或者缓存中,这个是根据业务情况来定的,我们在决定Session的存储方式的时候需要充分考虑到业务情况.

在Sessions的框架中,使用起来是非常简单的,我们首先要新建一个store变量,用于作为存储层的抽象,在这里我们以cookie-base为例

1
var store = sessions.NewCookieStore([]byte(os.Getenv("SESSION_KEY")))

然后我们在http的handler里面可以进行对象的引用,从而调用这个对象来进行Session的存取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func MyHandler(w http.ResponseWriter, r *http.Request) {
// Get a session.
session, err := store.Get(r, "session-name")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// Retrieve our struct and type-assert it
val := session.Values["person"]
var person = &Person{}
if person, ok := val.(*Person); !ok {
// Handle the case that it's not an expected type
}

// Get the previous flashes, if any.
if flashes := session.Flashes(); len(flashes) > 0 {
// Use the flash values.
} else {
// Set a new flash.
session.AddFlash("Hello, flash messages world!")
}
err = session.Save(r, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}

看完了基本的使用方法,我们来看看他们的实现方式

基于Cookie的Session存储其实有点像JWT的原理,将所有的信息放入Cookie中并进行加密,在服务端拿到Cookie后进行解密,但是这样的弊端在于其信息量会比较小,不可能放入较多信息,同时也没办法放入无法持久化的消息如Socket等等.

其获取和保存Session信息的基本流程如下

image-20200407161426672

Session为了安全,对信息进行编码加密,而密钥是我们在store.New时进行指定的.

关于图片和转载

知识共享许可协议
本作品采用知识共享署名 4.0 国际许可协议进行许可。 转载时请注明原文链接,图片在使用时请保留图片中的全部内容,可适当缩放并在引用处附上图片所在的文章链接,图片使用 Sketch 进行绘制,你可以在 技术文章配图指南 一文中找到画图的方法和素材。