跳转至

会话

会话允许你在多个请求之间持久化用户的数据。会话通过在初始化新会话时创建并返回一个唯一的 cookie 以及 HTTP 响应来工作。浏览器会自动检测到此 cookie, 并将其包含在未来的请求中。这允许 Vapor 在你的请求处理中自动恢复特定用户的会话。

会话非常适合内置在 Vapor 中的前端应用程序,这些应用程序直接向浏览器提供 HTML。对于 API,在请求之间保留用户数据,我们建议使用无状态、基于令牌的身份验证方式。

配置

要在路由中使用会话,请求必须通过 SessionsMiddleware 中间件。 最简单的实现方式是全局添加此中间件。建议你在声明 Cookie 后添加此代码。这是因为 Sessions 是一个结构体,它是一个值类型,而不是引用类型。因为它是值类型,所以必须先设置该值才能使用 SessionsMiddleware

app.middleware.use(app.sessions.middleware)

如果只有一部分路由使用会话,可以添加 SessionsMiddleware 中间件到路由组。

let sessions = app.grouped(app.sessions.middleware)

使用 app.sessions.configuration 配置会话生成的 HTTP cookie。你可以更改 cookie 名称并声明一个自定义函数来生成 cookie 值。

// 更改 cookie 名称为 ”foo“。
app.sessions.configuration.cookieName = "foo"

// 配置 cookie 值创建。
app.sessions.configuration.cookieFactory = { sessionID in
    .init(string: sessionID.string, isSecure: true)
}

app.middleware.use(app.sessions.middleware)

默认情况下,Vapor 将 vapor_session 作为 cookie 名称。

驱动

会话驱动程序负责按标识符存储和检索会话数据。你可以通过遵循 SessionDriver 协议来创建自定义驱动程序。

警告

应用程序中的会话驱动程序应在添加 app.sessions.middleware 前进行配置。

内存中

默认情况下,Vapor 使用内存中的会话。内存会话不需要配置,并且不会在应用程序启动之间持续存在,这使得它们非常适合测试。要手动启用内存会话,请使用 .memory 进行配置:

app.sessions.use(.memory)

对于生产用例,请查看其他会话驱动程序,在你的应用程序的多个实例之间它们利用数据库持久化和共享会话。

Fluent

Fluent 支持将会话数据存储在应用程序的数据库中。本节假设你已配置 Fluent 并且可以连接到数据库。第一步是启用 Fluent 会话驱动程序。

import Fluent

app.sessions.use(.fluent)

这将配置会话以使用应用程序的默认数据库。要指定特定数据库,请传递数据库的标识符。

app.sessions.use(.fluent(.sqlite))

最后,将 SessionRecord 迁移添加到数据库的迁移中。这将为在 _fluent_sessions 模式中存储会话数据准备好数据库。

app.migrations.add(SessionRecord.migration)

确保在添加新迁移后运行应用程序的迁移。会话现在将存储在你的应用的数据库中,允许它们在重新启动之间持久存在,并在应用程序的多个实例之间共享。

Redis

Redis 支持在你配置的 Redis 实例中存储会话数据。本部分假设你已配置 Redis,并且可以向 Redis 实例发送命令。

要使用 Redis 处理会话,请在配置应用程序时选择它:

import Redis

app.sessions.use(.redis)

这将配置会话以使用具有默认行为的 Redis 会话驱动程序。

也可以看看

了解有关 Redis 和 Sessions 的更多信息,请参阅Redis → Sessions

会话数据

配置好会话之后,就可以在请求之间持久化数据了。当数据添加到 req.session 时,新的会话会自动初始化。下面的示例展示了路由处理中接受一个动态路由参数,并将值添加到 req.session.data 中。

app.get("set", ":value") { req -> HTTPStatus in
    req.session.data["name"] = req.parameters.get("value")
    return .ok
}

使用以下请求来初始化一个名为 Vapor 的会话。

GET /set/vapor HTTP/1.1
content-length: 0

你应该会收到类似于以下内容的响应:

HTTP/1.1 200 OK
content-length: 0
set-cookie: vapor-session=123; Expires=Fri, 10 Apr 2020 21:08:09 GMT; Path=/

注意,在向 req.session 中添加数据后,set-cookie 被自动添加到响应头中。在后续请求中包含此 cookie 将允许访问会话数据。

添加以下路由处理以从会话中访问名称值。

app.get("get") { req -> String in
    req.session.data["name"] ?? "n/a"
}

使用以下请求访问此路由,同时确保传递上一个响应中的 cookie 值。

GET /get HTTP/1.1
cookie: vapor-session=123

你应该看到响应中返回的名称 Vapor。你可以根据需要在会话中添加或删除数据。在返回 HTTP 响应之前,会话数据将自动与会话驱动程序同步。

要结束会话,请使用 req.session.destroy 方法。 这将从会话驱动程序中删除数据并使会话 cookie 无效。

app.get("del") { req -> HTTPStatus in
    req.session.destroy()
    return .ok
}