Searching...

[TOC]

接口文档

https://godoc.org/github.com/gogf/gf/os/gsession

任何时候都可以通过ghttp.Request获取Session对象,因为CookieSession都是和请求会话相关,因此都属于Request的成员对象,并对外公开。gf框架的Session默认过期时间是24小时

SessionId默认通过Cookie来传递,并且也支持客户端通过Header传递SessionIdSessionId的名称通过ghttp.ServerSetSessionIdName进行修改。

此外,需要说明的是,Session的操作是支持并发安全的,这也是框架在对Session的设计上不采用直接以map的形式操作数据的原因。在任何时候,我们都可以通过ghttp.Request对象来修改和获取Session的全局相关属性。

gsession模块

GF v1.9开始,Session的管理功能单独解耦出来作为一个单独的模块,由gsession实现,并已完美整合到了ghttp.Server中。由于该模块是解耦独立的,因此可以使用到更多不同的场景中,例如:TCP通信、gRPC接口服务等等。

gsession模块中有三个对象/接口: 1. gsession.Manager:管理Session对象、Storage持久化存储对象、以及过期时间控制。 1. gsession.Session:单个Session会话管理对象,用于Session参数的增删查改等数据管理操作。 1. gsession.Storage:这是一个接口定义,用于Session对象的持久化存储、读取、存活更新操作,开发者可基于该接口实现自定义的持久化存储特性。该接口定义如下: “`go type Storage interface { // Get retrieves session value with given key. // It returns nil if the key does not exist in the session. Get(key string) interface{} // GetMap retrieves all key-value pairs as map from storage. GetMap() map[string]interface{} // GetSize retrieves the size of key-value pairs from storage. GetSize(id string) int

    // Set sets key-value session pair to the storage.
    Set(key string, value interface{}) error
    // SetMap batch sets key-value session pairs with map to the storage.
    SetMap(data map[string]interface{}) error

    // Remove deletes key with its value from storage.
    Remove(key string) error
    // RemoveAll deletes all key-value pairs from storage.
    RemoveAll() error

    // GetSession returns the session data bytes for given session id.
    GetSession(id string) map[string]interface{}
    // SetSession updates the content for session id.
    SetSession(id string, data map[string]interface{}) error

    // UpdateTTL updates the TTL for specified session id.
    UpdateTTL(id string) error
}
```

默认存储方式

默认的Session存储使用了内存+文件的方式。具体原理为: 1. Session的数据操作完全基于内存; 1. 使用gcache进程缓存模块控制数据过期; 1. 使用文件存储持久化存储管理Session数据; 1. 当且仅有当Session被标记为dirty时才会执行Session序列化并执行文件持久化存储; 1. 当且仅当内存中的Session不存在时,才会从文件存储中反序列化恢复Session数据到内存中; 1. 序列化/反序列化使用的是标准库的json.Marshal/UnMarshal方法;

从原理可知,当Session为读多写少的场景中,Session的数据操作非常高效。

有个注意的细节,由于文件存储涉及到文件操作,为便于降低IO开销并提高Session操作性能,并不是每一次Session请求结束后都即时地去更新存储的文件TTL时间。只有当涉及到写入操作时(被标记为dirty),这种情况下,每一次Session请求结束后会即时地更新对应Session存储文件的TTL时间;而针对于读取请求,将会每隔一分钟更新前一分钟内读取操作对应的Session文件TTL时间,以便于Session自动续活。

使用示例1,基本使用

package main

import (
    "github.com/gogf/gf/frame/g"
    "github.com/gogf/gf/net/ghttp"
)

func main() {
    s := g.Server()
    s.BindHandler("/session", func(r *ghttp.Request) {
        id := r.Session.GetInt("id")
        r.Session.Set("id", id + 1)
        r.Response.Write("id:", id)
    })
    s.SetPort(8199)
    s.Run()
}

启动main.go,访问 http://127.0.0.1:8199/session ,刷新几次页面,可以看到页面输出的id值在不断递增。

使用示例2,持久化示例

package main

import (
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"github.com/gogf/gf/os/gtime"
	"time"
)

func main() {
	s := g.Server()
	s.SetSessionMaxAge(10 * time.Second)
	s.BindHandler("/set", func(r *ghttp.Request) {
		r.Session.Set("time", gtime.Second())
		r.Response.Write("ok")
	})
	s.BindHandler("/get", func(r *ghttp.Request) {
		r.Response.WriteJson(r.Session.Map())
	})
	s.BindHandler("/clear", func(r *ghttp.Request) {
		r.Session.Clear()
	})
	s.SetPort(8199)
	s.Run()
}

执行后, 1. 首先,访问 http://127.0.0.1:8199/set 设置一个Session变量; 1. 随后,访问 http://127.0.0.1:8199/get 可以看到该Session变量已经设置并成功获取; 1. 接着,我们停止程序,并重新启动,再次访问 http://127.0.0.1:8199/get ,可以看到Session变量已经从文件存储中恢复并成功获取; 1. 等待10秒后,再次访问 http://127.0.0.1:8199/get 可以看到已经无法获取该Session,因为该Session已经过期;