实验性 sessions
类型: boolean
默认值: false
astro@5.1.0
会话(session)是用于存储 按需渲染页面 在请求间的用户状态。
该实验性功能允许你存储和读取诸如登录状态、购物车内容、或者是其他用户特定数据:
---export const prerender = false; // 选用 'server' 输出时无需配置const cart = await Astro.session.get('cart');---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>
会话依赖于一个 可配置的会话 driver
来将数据存储在 session
对象上。一个 会话 cookie 存储一个识别会话 ID。
session
对象 允许你和存储的用户状态(例如:添加物品至购物车)和会话 ID(例如:当退出登录时删除会话 ID)进行交互。
启用实验性 sessions
段落标题 启用实验性 sessions要启用会话,请将 experimental.session
标志设置为 true
。会话只会在按需渲染的页面上工作,所以你需要 安装适配器 以支持按需渲染,并确保每个使用会话的页面已经设置为 prerender: false
,或是在 Astro 配置中将 output
选项设置为 server
。
{ adapter: node({ mode: "standalone", }), experimental: { session: true, }, }
会话需要一个存储驱动来存储会话数据。Node 和 Netlify 适配器会自动为你配置一个默认的驱动,但其他的适配器目前仍需要你 手动指定驱动。你可以使用 unstorage 上任何支持的驱动。
配置会话驱动
段落标题 配置会话驱动如果你目前正在使用的适配器并没有默认驱动,又或者你想选择一个不同的驱动,那么你可以使用 session
配置选项来完成配置:
{ adapter: vercel(), session: { driver: "upstash", }, experimental: { session: true, }, }
使用与你的托管平台提供的存储功能相对应的 unstorage driver
名称来配置 session.driver
,例如 Cloudflare KV 驱动 或是 Deno KV 驱动。你也可以使用诸如 Upstash 或是 Redis 这样跨平台的驱动。
某些驱动可能会需要安装额外的包。例如 Upstash 需要安装 @upstash/redis
包。某些驱动程序可能还需要设置环境变量或凭据。
driver
名称、附加依赖项、使用方法等,请参阅 unstorage 驱动文档。
驱动选项
段落标题 驱动选项你还可以将 session.options
单独以对象的形式将任意的可用选项传入 unstorage 驱动。请参阅你选定驱动的文档以获取可用选项。
下面的示例设置了一个 base
前缀("sessions"
),用于升级 Upstash 中的所有键:
{ adapter: vercel(), session: { driver: "upstash", options: { base: "sessions", }, }, experimental: { session: true, }, }
其他会话选项
段落标题 其他会话选项你可以在 session
对象中为会话配置额外选项。
session.cookie
段落标题 session.cookie类型: string
| object
默认值: astro-session
用于配置会话 cookie 的选项。生成会话时,将在响应中设置此 cookie。cookie 中没有实际的用户数据存储——只有用于识别用户会话的 ID。session.cookie
选项可用于为此 cookie 设置选项。你可以提供一个 string
,该字符串将用作 cookie 的名称,也可以提供一个对象,该对象可用于配置其他额外选项:
{ session: { // 如果设置为一个字符串,则会将其用作 cookie 的名称 // cookie: "my-session-id", // 如果设置为一个对象,则允许配置高级选项 cookie: { name: "my-session-id" sameSite: "Strict", }, } }
session.ttl
段落标题 session.ttl类型: number
默认值: undefined
一个可选的默认选项,用于配置会话值直到过期的生存时间(以秒为单位)。
默认情况下,会话值会一直存续直到它们被删除或是会话被销毁,并且由于特定的时间已经过去,因此它们也不会自动过期。通过设置 session.ttl
能为你的会话值添加一个默认的过期时间。将 ttl
选项传递给 session.set()
将覆盖该单个条目的全局默认值。
{ session: { ttl: 60 * 60, // 1 个小时 } }
为会话值设置 ttl
不会在时间限制传入后自动从存储中将其删除。
存储中的值只会在 ttl
时间过期后尝试访问它们时,才会被删除。而此时,会话值将会为 undefined,而直到这时会话值才会被删除。
部分驱动程序同样支持 ttl
选项,该选项将在指定时间后自动删除会话。有关更多信息,请参阅你选定驱动的文档。
使用会话
段落标题 使用会话配置好驱动后,你就可以使用 session
对象与会话进行交互了。该对象可作为 Astro.session
从 Astro 组件和页面中以及 API 端点、中间件和 action 中的 context
对象上被读取到。所有情况下的 API 都是相同的。
会话将在首次使用时自动生成,会话也可以随时使用 Astro.session.regenerate()
重新生成,或使用 Astro.session.destroy()
销毁。
在大多数情况下,你只需使用 Astro.session.get()
和 Astro.session.set()
。有关其他可用方法,请参阅 API 部分。
Astro 组件和页面
段落标题 Astro 组件和页面在 .astro
组件和页面中,你可以通过全局 Astro
对象读取到会话对象。例如,要显示购物车中的商品数量:
---export const prerender = false; // 选用 'server' 输出时无需配置const cart = await Astro.session.get('cart');---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>
API 端点
段落标题 API 端点在 API 端点中,会话对象在 context
对象中可用。例如,要向购物车中添加一件商品:
import type { APIContext } from 'astro';
export async function POST(req: Request, context: APIContext) { const cart = await context.session.get('cart'); cart.push(req.body.item); await context.session.set('cart', cart); return Response.json(cart);}
Actions
段落标题 Actions在 action 中,会话对象在 context
对象中可用。例如,要向购物车中添加一件商品:
import { defineAction } from 'astro:actions';import { z } from 'astro:schema';
export const server = { addToCart: defineAction({ input: z.object({ productId: z.string() }), handler: async (input, context) => { const cart = await context.session.get('cart'); cart.push(input.productId); await context.session.set('cart', cart); return cart; }, }),};
中间件
段落标题 中间件edge middleware 目前暂不支持会话。
在中间件中,会话对象在 context
对象中可用。例如,在会话中设置最后访问的时间:
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => { context.session.set('lastVisit', new Date()); return next();});
会话数据类型
段落标题 会话数据类型默认情况下,会话数据的类型是未被定义的,你可以将任意数据存储在任何 key 中。使用 devalue 对值进行序列化和反序列化,该库与 content layer 和 action 使用的库相同。这意味着支持的类型是相同的,包括字符串、数字、Date
、Map
、Set
、URL
、数组和简单对象。
你可以通过创建 src/env.d.ts
文件并为 App.SessionData
添加类型,来选择性地为你的会话数据定义 TypeScript 类型:
declare namespace App { interface SessionData { user: { id: string; name: string; }; cart: string[]; }}
这将使你可以在编辑器中访问会话数据时,使用类型检查和自动补全:
---const cart = await Astro.session.get('cart');// const cart: string[] | undefined
const something = await Astro.session.get('something');// const something: any
Astro.session.set('user', { id: 1, name: 'Houston' });// Error: Argument of type '{ id: number; name: string }' is not assignable to parameter of type '{ id: string; name: string; }'.---
这仅用于类型检查,不会影响会话的运行时行为。如果你在用户使用会话来存储数据时更改了类型,请格外小心,因为这可能会导致运行时错误。
会话 API
段落标题 会话 API会话将在首次访问时自动创建。会话对象在所有 Astro 上下文中都可用,包括组件、action 和 API 端点。在组件中,它是通过全局 Astro
对象来读取到的,在 action 和 API 端点中,它在 context
对象中可用。所有情况下的 API 都是相同的。
session.get()
段落标题 session.get()类型: (key: string) => Promise<any>
返回会话中给定键的值。如果该键不存在,则返回 undefined
。
session.set()
段落标题 session.set()类型: (key: string, value: any, options?: { ttl: number }) => void
设置会话中给定键的值。该值可以是任何可序列化类型。该方法是同步的,该值可立即用于检索,但是直到请求结束之前,该方法才能保存到后端。
session.regenerate()
段落标题 session.regenerate()类型: () => void
重新生成会话 ID。最佳实践是在用户登录或升级权限时调用此方法,以防止会话固定攻击。
session.destroy()
段落标题 session.destroy()类型: () => void
销毁会话,从后端删除 cookie 和对象。当用户退出登录或会话无效时应调用此方法。
延伸阅读
段落标题 延伸阅读有关此实验性 API 的完整详细信息和反馈,请参阅 会话 RFC。
Reference