# 会话 会话允许你在多个请求之间持久化用户的数据。会话通过在初始化新会话时创建并返回一个唯一的 cookie 以及 HTTP 响应来工作。浏览器会自动检测到此 cookie, 并将其包含在未来的请求中。这允许 Vapor 在你的请求处理中自动恢复特定用户的会话。 会话非常适合内置在 Vapor 中的前端应用程序,这些应用程序直接向浏览器提供 HTML。对于 API,在请求之间保留用户数据,我们建议使用无状态、[基于令牌的身份验证](../security/authentication.md)方式。 ## 配置(Configuration) 要在路由中使用会话,请求必须通过 `SessionsMiddleware` 中间件。 最简单的实现方式是全局添加此中间件。建议你在声明 Cookie 后添加此代码。这是因为 Sessions 是一个结构体,它是一个值类型,而不是引用类型。因为它是值类型,所以必须先设置该值才能使用 `SessionsMiddleware`。 ```swift app.middleware.use(app.sessions.middleware) ``` 如果只有一部分路由使用会话,可以添加 `SessionsMiddleware` 中间件到路由组。 ```swift let sessions = app.grouped(app.sessions.middleware) ``` 使用 `app.sessions.configuration` 配置会话生成的 HTTP cookie。你可以更改 cookie 名称并声明一个自定义函数来生成 cookie 值。 ```swift // 更改 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` 协议来创建自定义驱动程序。 !!! warning "警告" 应用程序中的会话驱动程序应在添加 `app.sessions.middleware` 前进行配置。 ### 内存中 默认情况下,Vapor 使用内存中的会话。内存会话不需要配置,并且不会在应用程序启动之间持续存在,这使得它们非常适合测试。要手动启用内存会话,请使用 `.memory` 进行配置: ```swift app.sessions.use(.memory) ``` 对于生产用例,请查看其他会话驱动程序,在你的应用程序的多个实例之间它们利用数据库持久化和共享会话。 ### Fluent Fluent 支持将会话数据存储在应用程序的数据库中。本节假设你[已配置 Fluent](../fluent/overview.zh.md) 并且可以连接到数据库。第一步是启用 Fluent 会话驱动程序。 ```swift import Fluent app.sessions.use(.fluent) ``` 这将配置会话以使用应用程序的默认数据库。要指定特定数据库,请传递数据库的标识符。 ```swift app.sessions.use(.fluent(.sqlite)) ``` 最后,将 `SessionRecord` 迁移添加到数据库的迁移中。这将为在 `_fluent_sessions` 模式中存储会话数据准备好数据库。 ```swift app.migrations.add(SessionRecord.migration) ``` 确保在添加新迁移后运行应用程序的迁移。会话现在将存储在你的应用的数据库中,允许它们在重新启动之间持久存在,并在应用程序的多个实例之间共享。 ### Redis Redis 支持在你配置的 Redis 实例中存储会话数据。本部分假设你[已配置 Redis](../redis/overview.zh.md),并且可以向 Redis 实例发送命令。 要使用 Redis 处理会话,请在配置应用程序时选择它: ```swift import Redis app.sessions.use(.redis) ``` 这将配置会话以使用具有默认行为的 Redis 会话驱动程序。 !!! seealso "也可以看看" 了解有关 Redis 和 Sessions 的更多信息,请参阅[Redis → Sessions](../redis/sessions.zh.md)。 ## 会话数据 配置好会话之后,就可以在请求之间持久化数据了。当数据添加到 `req.session` 时,新的会话会自动初始化。下面的示例展示了路由处理中接受一个动态路由参数,并将值添加到 `req.session.data` 中。 ```swift app.get("set", ":value") { req -> HTTPStatus in req.session.data["name"] = req.parameters.get("value") return .ok } ``` 使用以下请求来初始化一个名为 Vapor 的会话。 ```http GET /set/vapor HTTP/1.1 content-length: 0 ``` 你应该会收到类似于以下内容的响应: ```http 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 将允许访问会话数据。 添加以下路由处理以从会话中访问名称值。 ```swift app.get("get") { req -> String in req.session.data["name"] ?? "n/a" } ``` 使用以下请求访问此路由,同时确保传递上一个响应中的 cookie 值。 ```http GET /get HTTP/1.1 cookie: vapor-session=123 ``` 你应该看到响应中返回的名称 Vapor。你可以根据需要在会话中添加或删除数据。在返回 HTTP 响应之前,会话数据将自动与会话驱动程序同步。 要结束会话,请使用 `req.session.destroy` 方法。 这将从会话驱动程序中删除数据并使会话 cookie 无效。 ```swift app.get("del") { req -> HTTPStatus in req.session.destroy() return .ok } ```