菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
0
0

GoWeb教程_06.1. session 和 cookie

原创
05/13 14:22
阅读数 381

session 和 cookie 是网站浏览中较为常见的两个概念,也是比较难以辨析的两个概念,但它们在浏览需要认证的服务页面以及页面统计中却相当关键。我们先来了解一下 session 和 cookie 怎么来的?考虑这样一个问题:

如何抓取一个访问受限的网页?如新浪微博好友的主页,个人微博页面等。

显然,通过浏览器,我们可以手动输入用户名和密码来访问页面,而所谓的 “抓取”,其实就是使用程序来模拟完成同样的工作,因此我们需要了解“登陆”过程中到底发生了什么。

当用户来到微博登陆页面,输入用户名和密码之后点击 “登录” 后浏览器将认证信息 POST 给远端的服务器,服务器执行验证逻辑,如果验证通过,则浏览器会跳转到登录用户的微博首页,在登录成功后,服务器如何验证我们对其他受限制页面的访问呢?因为 HTTP 协议是无状态的,所以很显然服务器不可能知道我们已经在上一次的 HTTP 请求中通过了验证。当然,最简单的解决方案就是所有的请求里面都带上用户名和密码,这样虽然可行,但大大加重了服务器的负担(对于每个 request 都需要到数据库验证),也大大降低了用户体验(每个页面都需要重新输入用户名密码,每个页面都带有登录表单)。既然直接在请求中带上用户名与密码不可行,那么就只有在服务器或客户端保存一些类似的可以代表身份的信息了,所以就有了 cookie 与 session。

cookie,简而言之就是在本地计算机保存一些用户操作的历史信息(当然包括登录信息),并在用户再次访问该站点时浏览器通过 HTTP 协议将本地 cookie 内容发送给服务器,从而完成验证,或继续上一步操作。

图 6.1 cookie 的原理图

session,简而言之就是在服务器上保存用户操作的历史信息。服务器使用 session id 来标识 session,session id 由服务器负责产生,保证随机性与唯一性,相当于一个随机密钥,避免在握手或传输中暴露用户真实密码。但该方式下,仍然需要将发送请求的客户端与 session 进行对应,所以可以借助 cookie 机制来获取客户端的标识(即 session id),也可以通过 GET 方式将 id 提交给服务器。

图 6.2 session 的原理图

cookie

Cookie 是由浏览器维持的,存储在客户端的一小段文本信息,伴随着用户请求和页面在 Web 服务器和浏览器之间传递。用户每次访问站点时,Web 应用程序都可以读取 cookie 包含的信息。浏览器设置里面有 cookie 隐私数据选项,打开它,可以看到很多已访问网站的 cookies,如下图所示:


图 6.3 浏览器端保存的 cookie 信息

cookie 是有时间限制的,根据生命期不同分成两种:会话 cookie 和持久 cookie;

如果不设置过期时间,则表示这个 cookie的生命周期为从创建到浏览器关闭为止,只要关闭浏览器窗口,cookie 就消失了。这种生命期为浏览会话期的 cookie 被称为会话 cookie。会话 cookie 一般不保存在硬盘上而是保存在内存里。

如果设置了过期时间 (setMaxAge(606024)),浏览器就会把 cookie 保存到硬盘上,关闭后再次打开浏览器,这些 cookie 依然有效直到超过设定的过期时间。存储在硬盘上的 cookie 可以在不同的浏览器进程间共享,比如两个 IE 窗口。而对于保存在内存的 cookie,不同的浏览器有不同的处理方式。   

Go 设置 cookie

Go 语言中通过 net/http 包中的 SetCookie 来设置:

http.SetCookie(w ResponseWriter, cookie *Cookie)

w 表示需要写入的 response,cookie 是一个 struct,让我们来看一下 cookie 对象是怎么样的

type Cookie struct {
    Name       string
    Value      string
    Path       string
    Domain     string
    Expires    time.Time
    RawExpires string

// MaxAge=0 means no 'Max-Age' attribute specified.
// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
// MaxAge>0 means Max-Age attribute present and given in seconds
    MaxAge   int
    Secure   bool
    HttpOnly bool
    Raw      string
    Unparsed []string // Raw text of unparsed attribute-value pairs
}

我们来看一个例子,如何设置 cookie

expiration := time.Now()
expiration = expiration.AddDate(1, 0, 0)
cookie := http.Cookie{Name: "username", Value: "astaxie", Expires: expiration}
http.SetCookie(w, &cookie)

  

Go 读取 cookie

上面的例子演示了如何设置 cookie 数据,我们这里来演示一下如何读取 cookie

cookie, _ := r.Cookie("username")
fmt.Fprint(w, cookie)

还有另外一种读取方式

for _, cookie := range r.Cookies() {
    fmt.Fprint(w, cookie.Name)
}

可以看到通过 request 获取 cookie 非常方便。

session

session,中文经常翻译为会话,其本来的含义是指有始有终的一系列动作/消息,比如打电话是从拿起电话拨号到挂断电话这中间的一系列过程可以称之为一个 session。然而当 session一词与网络协议相关联时,它又往往隐含了“面向连接”和/或“保持状态”这样两个含义。

session 在 Web 开发环境下的语义又有了新的扩展,它的含义是指一类用来在客户端与服务器端之间保持状态的解决方案。有时候 Session 也用来指这种解决方案的存储结构。

session 机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。

但程序需要为某个客户端的请求创建一个 session 的时候,服务器首先检查这个客户端的请求里是否包含了一个 session 标识-称为 session id,如果已经包含一个 session id 则说明以前已经为此客户创建过 session,服务器就按照 session id 把这个 session 检索出来使用(如果检索不到,可能会新建一个,这种情况可能出现在服务端已经删除了该用户对应的 session 对象,但用户人为地在请求的 URL 后面附加上一个 JSESSION 的参数)。如果客户请求不包含 session id,则为此客户创建一个 session 并且同时生成一个与此 session 相关联的 session id,这个 session id 将在本次响应中返回给客户端保存。

session 机制本身并不复杂,然而其实现和配置上的灵活性却使得具体情况复杂多变。这也要求我们不能把仅仅某一次的经验或者某一个浏览器,服务器的经验当作普遍适用的。

小结

如上文所述,session 和 cookie 的目的相同,都是为了克服 http 协议无状态的缺陷,但完成的方法不同。session 通过 cookie,在客户端保存 session id,而将用户的其他会话消息保存在服务端的 session 对象中,与此相对的,cookie 需要将所有信息都保存在客户端。因此 cookie 存在着一定的安全隐患,例如本地 cookie 中保存的用户名密码被破译,或 cookie 被其他网站收集(例如:1. appA 主动设置域 B cookie,让域 B cookie 获取;2. XSS,在 appA上通过 javascript 获取 document.cookie,并传递给自己的 appB)。

通过上面的一些简单介绍我们了解了 cookie 和 session 的一些基础知识,知道他们之间的联系和区别,做 web 开发之前,有必要将一些必要知识了解清楚,才不会在用到时捉襟见肘,或是在调 bug 时如无头苍蝇乱转。接下来的几小节我们将详细介绍 session 相关的知识。

发表评论

0/200
0 点赞
0 评论
收藏
为你推荐 换一批