在 Frontmatter 中获取数据
静态模式的数据获取
Astro 默认以静态生成(SSG)模式工作——构建时执行 frontmatter 代码,生成静态 HTML。这意味着你可以在 frontmatter 中直接调用任何 Node.js API,包括文件系统、数据库驱动等。
---
// 构建时执行,可以调用任何 Node.js API
import fs from 'node:fs/promises';
import { db } from '../lib/db';
// fetch API(Node 18+ 内置)
const response = await fetch('https://api.github.com/repos/withastro/astro');
const repo = await response.json();
// 读取本地文件
const config = JSON.parse(await fs.readFile('./config.json', 'utf-8'));
// 查询数据库(构建时)
const featuredPosts = await db.post.findMany({
where: { featured: true },
take: 3,
});
---
<h1>GitHub Stars: {repo.stargazers_count}</h1>
<ul>
{featuredPosts.map(p => <li>{p.title}</li>)}
</ul>
在 output: 'static' 模式下,数据只在构建时获取一次。如果 API 数据更新了,需要重新构建网站。对于频繁变化的数据,需要使用 SSR 模式或结合增量静态再生(ISR)。
启用 SSR:服务端渲染模式
安装适配器
# Vercel(推荐)
npx astro add vercel
# Netlify
npx astro add netlify
# Node.js 自托管
npx astro add node
# Cloudflare Workers/Pages
npx astro add cloudflare
// astro.config.mjs - SSR 配置
import { defineConfig } from 'astro/config';
import vercel from '@astrojs/vercel/serverless';
export default defineConfig({
output: 'server', // 全站 SSR
adapter: vercel(),
});
// 或者混合模式:默认 SSG,个别页面启用 SSR
export default defineConfig({
output: 'hybrid', // 混合模式(Astro 2.6+)
adapter: vercel(),
});
SSR 页面中的请求对象
---
// 在 output: 'server' 或 output: 'hybrid' + export const prerender = false 时
export const prerender = false; // 混合模式时明确声明此页面为 SSR
// Astro.request:当前请求的 Request 对象
const url = new URL(Astro.request.url);
const searchQuery = url.searchParams.get('q') ?? '';
// 读取请求头
const userAgent = Astro.request.headers.get('user-agent');
// 读取 Cookie
const cookie = Astro.cookies.get('session');
const sessionId = cookie?.value;
// 读取 POST 请求 body
if (Astro.request.method === 'POST') {
const formData = await Astro.request.formData();
const username = formData.get('username');
}
// 设置响应头
Astro.response.headers.set('Cache-Control', 'private, max-age=0');
---
<p>搜索:{searchQuery}</p>
API 路由
创建 API 端点
// src/pages/api/users.ts
import type { APIRoute } from 'astro';
import { db } from '../../lib/db';
export const GET: APIRoute = async ({ request, params }) => {
const users = await db.user.findMany();
return new Response(JSON.stringify(users), {
status: 200,
headers: { 'Content-Type': 'application/json' },
});
};
export const POST: APIRoute = async ({ request }) => {
const body = await request.json();
const user = await db.user.create({ data: body });
return new Response(JSON.stringify(user), { status: 201 });
};
环境变量
# .env 文件
DATABASE_URL=postgresql://localhost/mydb
API_SECRET=your-secret-key-here
# PUBLIC_ 前缀的变量可在客户端访问
PUBLIC_API_BASE_URL=https://api.example.com
---
// 服务端(frontmatter)可访问所有环境变量
const dbUrl = import.meta.env.DATABASE_URL;
const secret = import.meta.env.API_SECRET;
// PUBLIC_ 前缀的变量在客户端也可访问
const apiBase = import.meta.env.PUBLIC_API_BASE_URL;
---
不带 PUBLIC_ 前缀的环境变量(如 DATABASE_URL、API_SECRET)只在服务端 frontmatter 中可访问,不会被打包到客户端 JS 中。带 PUBLIC_ 前缀的变量会嵌入到客户端 JS 中,所有用户都能在浏览器中查看,切勿存放密钥。
SSG vs SSR 的核心区别
Astro.locals:SSR 中间件通信
// src/middleware.ts(Astro 中间件)
import { defineMiddleware } from 'astro:middleware';
import { verifyJWT } from './lib/auth';
// 中间件在每个请求时运行,可以向 locals 注入数据
export const onRequest = defineMiddleware(async (context, next) => {
const token = context.cookies.get('session')?.value;
if (token) {
const user = await verifyJWT(token);
// 将用户信息注入到 locals,所有 Astro 页面/API 都能访问
context.locals.user = user;
}
// 保护路由:未登录则重定向
if (context.url.pathname.startsWith('/dashboard') && !context.locals.user) {
return context.redirect('/login');
}
return next();
});
// 在页面中使用 locals
// const { user } = Astro.locals;
Astro Actions:类型安全的服务端函数
Astro Actions(Astro 5 稳定版特性)是一种在服务端定义、在客户端调用的 RPC 机制。不同于传统 API 路由,Actions 提供全链路 TypeScript 类型安全:输入参数由 zod 验证,返回值类型自动推断,客户端调用无需手写 fetch 代码。
定义 Actions
// src/actions/index.ts
import { defineAction, ActionError } from 'astro:actions';
import { z } from 'astro:schema';
export const server = {
// 发送联系表单的 Action
contact: defineAction({
// input 使用 zod 验证,自动生成 TypeScript 类型
input: z.object({
name: z.string().min(1, '姓名不能为空'),
email: z.string().email('邮箱格式不正确'),
message: z.string().min(10, '消息至少 10 个字符'),
}),
// handler 在服务端执行,可访问数据库、发送邮件等
handler: async ({ name, email, message }) => {
const result = await db.contact.create({
data: { name, email, message, createdAt: new Date() }
});
// 发送通知邮件
await sendEmail({ to: 'admin@example.com', subject: `新留言来自 ${name}` });
return { id: result.id, success: true };
},
}),
// 需要认证的 Action
updateProfile: defineAction({
input: z.object({
displayName: z.string().optional(),
bio: z.string().max(200).optional(),
}),
handler: async (input, context) => {
// context 包含 request、cookies、locals(中间件注入的数据)
const user = context.locals.user;
if (!user) {
throw new ActionError({
code: 'UNAUTHORIZED',
message: '请先登录',
});
}
return db.user.update({ where: { id: user.id }, data: input });
},
}),
};
在客户端调用 Actions
---
// src/pages/contact.astro
import { actions } from 'astro:actions';
---
<form>
<input name="name" placeholder="姓名" required />
<input name="email" type="email" placeholder="邮箱" required />
<textarea name="message" placeholder="留言"></textarea>
<button type="submit">发送</button>
</form>
<script>
import { actions } from 'astro:actions';
document.querySelector('form')?.addEventListener('submit', async (e) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
// 类型安全调用:参数类型由 zod schema 推断,返回值类型自动推断
const { data, error } = await actions.contact(formData);
if (error) {
// error.code 是字符串枚举(BAD_REQUEST / UNAUTHORIZED 等)
console.error(error.message);
return;
}
// data 类型完全推断自 handler 返回值
console.log(`提交成功,ID: ${data.id}`);
});
</script>
Actions 适合表单提交、RPC 风格调用(明确的输入/输出),以及需要 TypeScript 端到端类型安全的场景。API Routes 更灵活,适合:需要精细控制 HTTP 响应格式、实现 RESTful 资源端点(供外部调用)、或处理文件上传流等低级别 HTTP 操作的场景。两者可以在同一项目中共存。
Astro Actions 在底层通过 POST 请求到特殊端点实现,因此需要服务器运行时(安装适配器并开启 output: 'server' 或 output: 'hybrid')。纯静态模式(output: 'static')无法使用 Actions——表单提交后无处理服务器。在 Cloudflare Workers 等边缘环境中,Actions 工作正常,但需要确保 handler 中不使用 Node.js 专有 API。
本章小结
- 静态模式数据获取:frontmatter 在构建时执行,可调用任何 Node.js API(数据库、文件系统、HTTP fetch);数据被硬编码进生成的 HTML,不会每次请求重新查询。
- SSR 激活方式:安装平台适配器(vercel/netlify/node/cloudflare)+ 设置 output: 'server' 或 output: 'hybrid';混合模式用 export const prerender = false 按需启用 SSR。
- SSR 请求对象:Astro.request(Request 对象)、Astro.cookies(Cookie 读写)、Astro.url(URL 解析)、Astro.response(设置响应头/状态码)——SSR 页面拥有完整的 HTTP 上下文。
- API 路由:pages/ 下的 .ts/.js 文件导出 GET/POST 等命名函数成为 API 端点;返回标准 Web API Response 对象;支持读取请求 body/params/headers。
- Astro Actions:Astro 5 的类型安全 RPC 机制;在 src/actions/index.ts 中定义(zod 验证输入,handler 执行服务端逻辑);客户端通过 actions.xxx() 调用,返回 { data, error } 结构;适合表单提交和需要端到端类型安全的交互。
- 中间件统一处理:src/middleware.ts 定义跨请求的通用逻辑(认证验证、日志、A/B 测试);通过 locals 向页面传递处理结果,避免在每个页面重复验证。