Session Storages

预计阅读时间:2分钟

有两个预定义的存储: SessionStorageMemoryDirectoryStorage . 另一个可组合的存储: CacheStorage .

DirectoryStorageCacheStorage取决于io.ktor:ktor-server-sessions:$ktor_version工件.

在这种模式下,您只是发送一个会话ID,而不是实际的会话内容. 该id用于使用特定的SessionStorage在服务器端存储其内容. 当您在cookieheader方法中指定带有存储的第二个参数时,将使用此模式.

Example:

install(Sessions) {
    cookie<SampleSession>("SESSION_FEATURE_SESSION_ID", SessionStorageMemory()) {
        cookie.path = "/"
    }
}

Custom SessionStorage

SessionStorage负责存储和检索会话有效负载. 接口是可挂起的 ,因此您可以并且应该尽可能异步地传输数据.

数据作为流传输,被调用方将通过提供二进制有效负载的使用者和提供者,并且被调用方将负责打开和关闭那些字节通道.

interface SessionStorage {
    suspend fun write(id: String, provider: suspend (ByteWriteChannel) -> Unit)
    suspend fun invalidate(id: String)
    suspend fun <R> read(id: String, consumer: suspend (ByteReadChannel) -> R): R
}

如果存储没有提供将信息作为流存储的有意义的方式,则可能需要使用简化的适配器,该适配器仅使用ByteArray对其进行读写. 它也可以用作示例,以了解如何在其原始的基于流的版本中处理API.

SimplifiedSessionStorage.kt
abstract class SimplifiedSessionStorage : SessionStorage {
    abstract suspend fun read(id: String): ByteArray?
    abstract suspend fun write(id: String, data: ByteArray?): Unit

    override suspend fun invalidate(id: String) {
        write(id, null)
    }

    override suspend fun <R> read(id: String, consumer: suspend (ByteReadChannel) -> R): R {
        val data = read(id) ?: throw NoSuchElementException("Session $id not found")
        return consumer(ByteReadChannel(data))
    }

    override suspend fun write(id: String, provider: suspend (ByteWriteChannel) -> Unit) {
        return provider(reader(coroutineContext, autoFlush = true) {
            write(id, channel.readAvailable())
        }.channel)
    }
}

suspend fun ByteReadChannel.readAvailable(): ByteArray {
    val data = ByteArrayOutputStream()
    val temp = ByteArray(1024)
    while (!isClosedForRead) {
        val read = readAvailable(temp)
        if (read <= 0) break
        data.write(temp, 0, read)
    }
    return data.toByteArray()
}

by  ICOPY.SITE