跳转到内容

实验性 sessions

类型: boolean
默认值: false

添加于: astro@5.1.0

会话(session)是用于存储 按需渲染页面 在请求间的用户状态。

该实验性功能允许你存储和读取诸如登录状态、购物车内容、或者是其他用户特定数据:

src/components/CartButton.astro
---
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)进行交互。

要启用会话,请将 experimental.session 标志设置为 true。会话只会在按需渲染的页面上工作,所以你需要 安装适配器 以支持按需渲染,并确保每个使用会话的页面已经设置为 prerender: false,或是在 Astro 配置中将 output 选项设置为 server

astro.config.mjs
{
adapter: node({
mode: "standalone",
}),
experimental: {
session: true,
},
}

会话需要一个存储驱动来存储会话数据。Node 和 Netlify 适配器会自动为你配置一个默认的驱动,但其他的适配器目前仍需要你 手动指定驱动。你可以使用 unstorage 上任何支持的驱动

如果你目前正在使用的适配器并没有默认驱动,又或者你想选择一个不同的驱动,那么你可以使用 session 配置选项来完成配置:

astro.config.mjs
{
adapter: vercel(),
session: {
driver: "upstash",
},
experimental: {
session: true,
},
}

使用与你的托管平台提供的存储功能相对应的 unstorage driver 名称来配置 session.driver,例如 Cloudflare KV 驱动 或是 Deno KV 驱动。你也可以使用诸如 Upstash 或是 Redis 这样跨平台的驱动。

你还可以将 session.options 单独以对象的形式将任意的可用选项传入 unstorage 驱动。请参阅你选定驱动的文档以获取可用选项。

下面的示例设置了一个 base 前缀("sessions"),用于升级 Upstash 中的所有键:

astro.config.mjs
{
adapter: vercel(),
session: {
driver: "upstash",
options: {
base: "sessions",
},
},
experimental: {
session: true,
},
}

你可以在 session 对象中为会话配置额外选项。

类型: string | object
默认值: astro-session

用于配置会话 cookie 的选项。生成会话时,将在响应中设置此 cookie。cookie 中没有实际的用户数据存储——只有用于识别用户会话的 ID。session.cookie 选项可用于为此 cookie 设置选项。你可以提供一个 string,该字符串将用作 cookie 的名称,也可以提供一个对象,该对象可用于配置其他额外选项:

astro.config.mjs
{
session: {
// 如果设置为一个字符串,则会将其用作 cookie 的名称
// cookie: "my-session-id",
// 如果设置为一个对象,则允许配置高级选项
cookie: {
name: "my-session-id"
sameSite: "Strict",
},
}
}

类型: number
默认值: undefined

一个可选的默认选项,用于配置会话值直到过期的生存时间(以秒为单位)。

默认情况下,会话值会一直存续直到它们被删除或是会话被销毁,并且由于特定的时间已经过去,因此它们也不会自动过期。通过设置 session.ttl 能为你的会话值添加一个默认的过期时间。将 ttl 选项传递给 session.set() 将覆盖该单个条目的全局默认值。

astro.config.mjs
{
session: {
ttl: 60 * 60, // 1 个小时
}
}

配置好驱动后,你就可以使用 session 对象与会话进行交互了。该对象可作为 Astro.session 从 Astro 组件和页面中以及 API 端点、中间件和 action 中的 context 对象上被读取到。所有情况下的 API 都是相同的。

会话将在首次使用时自动生成,会话也可以随时使用 Astro.session.regenerate() 重新生成,或使用 Astro.session.destroy() 销毁。

在大多数情况下,你只需使用 Astro.session.get()Astro.session.set()。有关其他可用方法,请参阅 API 部分

.astro 组件和页面中,你可以通过全局 Astro 对象读取到会话对象。例如,要显示购物车中的商品数量:

src/components/CartButton.astro
---
export const prerender = false; // 选用 'server' 输出时无需配置
const cart = await Astro.session.get('cart');
---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>

在 API 端点中,会话对象在 context 对象中可用。例如,要向购物车中添加一件商品:

src/pages/api/addToCart.ts
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);
}

在 action 中,会话对象在 context 对象中可用。例如,要向购物车中添加一件商品:

src/actions/addToCart.ts
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;
},
}),
};

在中间件中,会话对象在 context 对象中可用。例如,在会话中设置最后访问的时间:

src/middleware.ts
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 使用的库相同。这意味着支持的类型是相同的,包括字符串、数字、DateMapSetURL、数组和简单对象。

你可以通过创建 src/env.d.ts 文件并为 App.SessionData 添加类型,来选择性地为你的会话数据定义 TypeScript 类型:

src/env.d.ts
declare namespace App {
interface SessionData {
user: {
id: string;
name: string;
};
cart: string[];
}
}

这将使你可以在编辑器中访问会话数据时,使用类型检查和自动补全:

src/components/CartButton.astro
---
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; }'.
---

会话将在首次访问时自动创建。会话对象在所有 Astro 上下文中都可用,包括组件、action 和 API 端点。在组件中,它是通过全局 Astro 对象来读取到的,在 action 和 API 端点中,它在 context 对象中可用。所有情况下的 API 都是相同的。

类型: (key: string) => Promise<any>

返回会话中给定键的值。如果该键不存在,则返回 undefined

类型: (key: string, value: any, options?: { ttl: number }) => void

设置会话中给定键的值。该值可以是任何可序列化类型。该方法是同步的,该值可立即用于检索,但是直到请求结束之前,该方法才能保存到后端。

类型: () => void

重新生成会话 ID。最佳实践是在用户登录或升级权限时调用此方法,以防止会话固定攻击。

类型: () => void

销毁会话,从后端删除 cookie 和对象。当用户退出登录或会话无效时应调用此方法。

有关此实验性 API 的完整详细信息和反馈,请参阅 会话 RFC

贡献 社区 赞助