会话功能从 astro@5.7.0 加入,用于在按需渲染页面的不同请求间共享数据。
与 cookies 直接保存数据不同,会话数据保存在服务端,适合用户数据、购物车、表单状态,也可以无需客户端 JavaScript 工作。服务端存储减轻了浏览器 Cookie 的数据容量限制,但仍须考虑存储后端容量、身份验证、访问控制和会话安全,不能将原文“无需担心安全问题”的说法当作自动保证。
例如,src/components/CartButton.astro 显示购物车数量:
---
export const prerender = false; // Not needed with 'server' output
const cart = await Astro.session?.get('cart');
---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>
配置会话
会话需要一个存储驱动。Node、Cloudflare、Netlify适配器会配置默认驱动;其他适配器目前需要手动指定驱动。
原文的 astro.config.mjs 示例为 Vercel 适配器指定 LRU cache 驱动:
import { defineConfig, sessionDrivers } from 'astro/config'
import vercel from '@astrojs/vercel'
export default defineConfig({
adapter: vercel(),
session: {
driver: sessionDrivers.lruCache({
max: 800,
}),
}
})
LRU cache 存储不能据此当作跨实例共享或持久化数据库;应根据部署方式选择适合的驱动。其他可配置选项见 session 配置。
在运行时覆盖配置
默认情况下,驱动在构建时配置,使用的环境变量会内联到构建结果中,因此不能直接在运行时覆盖。
需要连接外部服务等运行时配置时,可以在独立文件中定义驱动,然后将它设为驱动入口。
原文利用 Unstorage 兼容能力配置 Redis。
先安装 unstorage 和 ioredis。下面三种包管理器命令选一种:
npm install unstorage ioredis
pnpm add unstorage ioredis
yarn add unstorage ioredis
在 src/session-driver.ts 中导出默认函数,返回驱动实例:
import type { SessionDriver } from "astro";
import redisDriver from "unstorage/drivers/redis";
import { REDIS_HOST, REDIS_PORT } from "astro:env/server";
export default function (): SessionDriver {
const driver = redisDriver({
host: REDIS_HOST,
port: REDIS_PORT,
});
return {
async getItem(key) {
return await driver.getItem(key);
},
async setItem(key, value) {
await driver.setItem?.(key, value, {});
},
async removeItem(key) {
await driver.removeItem?.(key, {});
},
};
}
随后在 astro.config.mjs 中引用该入口:
import { defineConfig, envField, sessionDrivers } from "astro/config";
import vercel from "@astrojs/vercel";
export default defineConfig({
adapter: vercel(),
env: {
schema: {
REDIS_HOST: envField.string({
context: "server",
access: "public",
default: "localhost",
}),
REDIS_PORT: envField.number({
context: "server",
access: "public",
default: 6379,
}),
},
},
session: {
driver: {
entrypoint: new URL("./src/session-driver.ts", import.meta.url),
},
},
});
这样,驱动函数在运行时获取配置。示例还声明了服务端环境字段 REDIS_HOST 和 REDIS_PORT。示例默认主机和端口只是配置值,不代表已建立 Redis 连接;实际需要确保后端、部署环境和权限均可用。
禁用会话
session: false 从 astro@7.2.0 加入。
当没有配置会话驱动时,会话运行时代码自动从服务器包中排除。显式设置 session: false 还会要求适配器不要提供默认驱动,从而完全关闭项目的会话支持:
import { defineConfig } from 'astro/config';
export default defineConfig({
session: false,
});
原本提供默认驱动的 Node、Cloudflare、Netlify 等适配器也不会再配置驱动。原文说明,这可在 serverless 与 edge 运行环境中减小包体、帮助减少冷启动时间;本稿未测量具体收益。
访问会话数据
session 对象用于读写用户状态和管理会话 ID,例如添加购物车项目,或退出时清除会话 ID Cookie。
在 Astro 组件及页面中通过 Astro.session 访问;在 API endpoint、中间件与 actions 中通过 context.session 访问。
首次使用时自动创建会话。可调用 session.regenerate()重新生成,或调用 session.destroy()销毁。常见读写主要使用 session.get() 与 session.set(),完整说明见 Sessions API。
Astro 组件和页面
在 .astro 组件和页面中使用全局 Astro 对象。原文再次给出 src/components/CartButton.astro:
---
export const prerender = false; // Not needed with 'server' output
const cart = await Astro.session?.get('cart');
---
<a href="/checkout">🛒 {cart?.length ?? 0} items</a>
该例用 prerender = false 使页面按需渲染;原文注明 server 输出模式不需要这一行。
API endpoints
src/pages/api/addToCart.ts 从请求中读取项目,再保存购物车:
import type { APIContext } from "astro";
export async function POST(context: APIContext) {
const cart = await context.session?.get('cart') || [];
const data = await context.request.json();
if(!data?.item) {
return new Response('Item is required', { status: 400 });
}
cart.push(data.item);
await context.session?.set('cart', cart);
return Response.json(cart);
}
原例先以空数组初始化缺失的购物车,检查是否提供 item,否则返回 400。这个最小检查不等于完整鉴权或输入验证;实际接口还需按业务约束处理。
Actions
在 src/actions/addToCart.ts 中通过 action 的 context 访问会话:
import { defineAction } from 'astro:actions';
import { z } from 'astro/zod';
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.session?.get('cart') 可能返回 undefined,随后直接 cart.push 就会失败。实际实现需确保会话已启用、购物车已初始化,并对读取结果正确处理。这里没有改动原文代码,也不声称示例已运行通过。
中间件
原文注明会话不支持 edge middleware。
一般中间件中可以通过 context 更新最后访问时间,src/middleware.ts 如下:
import { defineMiddleware } from 'astro:middleware';
export const onRequest = defineMiddleware(async (context, next) => {
context.session?.set('lastVisit', new Date());
return next();
});
示例保留了未等待 set 的原写法。实际存储完成时机、错误处理和部署环境须按使用的驱动与 API 契约验证。
会话数据类型
默认会话数据没有类型约束,可以在任意键中存值。序列化和反序列化使用 devalue,与内容集合和 actions 使用的库相同。支持字符串、数字、Date、Map、Set、URL、数组和普通对象。
可以在 src/env.d.ts 中扩展 App.SessionData,提供 TypeScript 类型:
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; }'.
---
这里 user.id 声明为字符串,传入数字会触发类型错误;未声明的键仍可能表现为 any。
这些声明只影响类型检查,不改变运行时会话行为,也不会验证历史数据。已经存有旧数据时更改类型,需要特别注意运行时不兼容。
来源:Astro 文档团队,当前英文原文,核对日期 2026-10-03。文档仓库许可为 MIT。本文译为中文,保留 5.7.0 与 7.2.0 的功能边界,说明容量、安全与未初始化购物车的前置条件;全部原文代码保留原样,未安装依赖、连接 Redis 或运行应用。完整许可通知如下。
MIT License
Copyright (c) 2022 withastro
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.











暂无评论内容