mirror of https://github.com/vapor/docs.git
79 lines
3.3 KiB
Markdown
79 lines
3.3 KiB
Markdown
# Redis & 会话
|
|
|
|
Redis 可以作为一个存储提供程序,用于缓存[会话数据](../advanced/sessions.md#session-data),例如用户凭据。
|
|
|
|
如果 [`RedisSessionsDelegate`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate) 未提供自定义委托,则将使用默认值。
|
|
|
|
## 默认行为
|
|
|
|
### 创建 SessionID
|
|
|
|
除非在你自己的 [`RedisSessionsDelegate`](#redissessionsdelegate) 中实现 [`makeNewID()`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate/makenewid()-3hyne) 方法,否则所有的 ['SessionID`](https://api.vapor.codes/vapor/documentation/vapor/sessionid) 值将通过以下操作创建:
|
|
|
|
1. 生成32字节的随机字符
|
|
1. base64 编码该值
|
|
|
|
例如:`Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=`
|
|
|
|
### 存储会话数据
|
|
|
|
`RedisSessionsDelegate` 的默认实现将使用 `Codable` 将 [`SessionData`](https://api.vapor.codes/vapor/documentation/vapor/sessiondata) 存储为一个简单的JSON字符串值。
|
|
|
|
除非在你自己的 `RedisSessionsDelegate` 中实现了 [`makeRedisKey(for:)`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate/makerediskey(for:)-5nfge) 方法,`SessionData` 将存储在 Redis 中,其中的键会在 `SessionID` 前加上前缀 `vrs-` (**V**apor **R**edis **S**essions)。
|
|
|
|
例如:`vrs-Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=`
|
|
|
|
## 注册自定义委托
|
|
|
|
要自定义数据从 Redis 读取和写入的方式,按如下方式注册 `RedisSessionsDelegate` 对象:
|
|
|
|
```swift
|
|
import Redis
|
|
|
|
struct CustomRedisSessionsDelegate: RedisSessionsDelegate {
|
|
// implementation
|
|
}
|
|
|
|
app.sessions.use(.redis(delegate: CustomRedisSessionsDelegate()))
|
|
```
|
|
|
|
## RedisSessionsDelegate
|
|
|
|
> API 文档:[`RedisSessionsDelegate`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate)
|
|
|
|
遵循该协议的对象可以用来改变 `SessionData` 在 Redis 中的存储方式。
|
|
|
|
符合协议的类型只需要实现两个方法:[`redis(_:store:with:)`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate/redis(_:store:with:)) 和 [`redis(_:fetchDataFor:)`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate/redis(_:fetchdatafor:))
|
|
|
|
这两者都是必需的,因为你自定义写入会话数据到 Redis 的方式本质上是与如何从 Redis 读取它有内在联系。
|
|
|
|
### RedisSessionsDelegate 哈希示例
|
|
|
|
例如,如果你想将会话数据作为 [Hash 存储在 Redis 中](https://redis.io/topics/data-types-intro#redis-hashes),你将实现如下内容:
|
|
|
|
```swift
|
|
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
|
|
}
|
|
}
|
|
}
|
|
```
|