跳转至

Redis & 会话

Redis 可以作为一个存储提供程序,用于缓存会话数据,例如用户凭据。

如果 RedisSessionsDelegate 未提供自定义委托,则将使用默认值。

默认行为

创建 SessionID

除非在你自己的 RedisSessionsDelegate 中实现 makeNewID() 方法,否则所有的 'SessionID` 值将通过以下操作创建:

  1. 生成32字节的随机字符
  2. base64 编码该值

例如:Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=

存储会话数据

RedisSessionsDelegate 的默认实现将使用 CodableSessionData 存储为一个简单的JSON字符串值。

除非在你自己的 RedisSessionsDelegate 中实现了 makeRedisKey(for:) 方法,SessionData 将存储在 Redis 中,其中的键会在 SessionID 前加上前缀 vrs- (Vapor Redis Sessions)。

例如:vrs-Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=

注册自定义委托

要自定义数据从 Redis 读取和写入的方式,按如下方式注册 RedisSessionsDelegate 对象:

import Redis

struct CustomRedisSessionsDelegate: RedisSessionsDelegate {
    // implementation
}

app.sessions.use(.redis(delegate: CustomRedisSessionsDelegate()))

RedisSessionsDelegate

API 文档:RedisSessionsDelegate

遵循该协议的对象可以用来改变 SessionData 在 Redis 中的存储方式。

符合协议的类型只需要实现两个方法:redis(_:store:with:)redis(_:fetchDataFor:)

这两者都是必需的,因为你自定义写入会话数据到 Redis 的方式本质上是与如何从 Redis 读取它有内在联系。

RedisSessionsDelegate 哈希示例

例如,如果你想将会话数据作为 Hash 存储在 Redis 中,你将实现如下内容:

func redis<Client: RedisClient>(
    _ client: Client,
    store data: SessionData,
    with key: RedisKey
) -> EventLoopFuture<Void> {
    // 将每个数据字段存储为单独的哈希字段
    return client.hmset(data.snapshot, in: key)
}
func redis<Client: RedisClient>(
    _ client: Client,
    fetchDataFor key: RedisKey
) -> EventLoopFuture<SessionData?> {
    return client
        .hgetall(from: key)
        .map { hash in
            // hash 是 [String: RESPValue] 这种类型,因此我们需要尝试解包为字符串
            // 并将每个值存储在数据容器中
            return hash.reduce(into: SessionData()) { result, next in
                guard let value = next.value.string else { return }
                result[next.key] = value
            }
        }
}