会话¶
会话允许你在多个请求之间持久化用户的数据。会话通过在初始化新会话时创建并返回一个唯一的 cookie 以及 HTTP 响应来工作。浏览器会自动检测到此 cookie, 并将其包含在未来的请求中。这允许 Vapor 在你的请求处理中自动恢复特定用户的会话。
会话非常适合内置在 Vapor 中的前端应用程序,这些应用程序直接向浏览器提供 HTML。对于 API,在请求之间保留用户数据,我们建议使用无状态、基于令牌的身份验证方式。
配置(Configuration)¶
要在路由中使用会话,请求必须通过 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
}