跳转到内容

Actions API 参考

添加于: astro@4.15.0

Action 帮助你构建一个类型安全的后端,你可以从客户端代码和 HTML 表单中调用它。所有用于定义和调用 Action 的工具函数都由 astro:actions 模块暴露。有关示例和使用说明,请参阅 Actions 指南

import {
actions,
defineAction,
isInputError,
isActionError,
ActionError,
} from 'astro:actions';

添加于: astro@4.15.0

defineAction() 函数接受一个 handler() 函数,其中包含在调用 Action 时要运行的服务器逻辑,以及一个可选的 input 属性,用于在运行时验证输入参数。

export const server = {
getGreeting: defineAction({
input: z.object({
name: z.string(),
}),
handler: async (input, context) => {
return `Hello, ${input.name}!`
}
})
}

类型:(input, context) => any

defineAction() 函数接受一个 handler() 函数,其中包含在调用 Action 时要运行的服务器逻辑。此函数可以返回数据,这些数据将自动序列化并发送给调用者。

handler() 函数被调用时,接受用户输入作为其第一个参数。如果设置了 input 验证器,那么用户输入将在传递给 handler() 前进行验证。第二个参数是一个 context 对象,包含大多数 Astro 的 标准端点上下文,不包括 getActionResult(), callAction(), 和 redirect()

返回值使用 devalue 库 进行解析。它支持 JSON 值,以及 Date(), Map(), Set(), 或 URL() 的实例。

类型:ZodType | undefined

可选的 input 属性接受一个 Zod 验证器(例如,Zod 对象,Zod 可区分联合),用于在运行时验证处理程序的输入。如果 action 验证失败,将返回 BAD_REQUEST 错误 并跳过 handler

如果省略 input,则 handler 将接收 JSON 请求的 unknown 类型的输入,以及表单请求的 FormData 类型。

如果你的 action 接受表单输入,请使用 z.object() 验证器将表单数据自动解析为类型化对象。表单数据字段支持以下验证器:

  • 使用 z.number() 验证类型为 number 的输入
  • 使用 z.boolean() 验证类型为 checkbox 的输入
  • 使用 z.instanceof(File) 验证类型为 file 的输入
  • 使用 z.array(/* validator */) 验证相同 name 的多个输入
  • 使用 z.string() 验证所有其他输入

z.object() 验证器还支持包括 .refine(), .transform(), 和 .pipe() 在内的扩展函数。

要搭配应用不同验证器的组合,请使用 z.discriminatedUnion() 包装器,它根据表单的特定字段以缩小类型范围。此示例通过接受表单提交以判断是 “创建(create)” 或是 “更新(update)” 了一名用户信息,判断时使用表单域的 type 属性字段来确定要验证的对象:

import { defineAction } from 'astro:actions';
import { z } from 'astro:schema';
export const server = {
changeUser: defineAction({
accept: 'form',
input: z.discriminatedUnion('type', [
z.object({
// 当 `type` 字段中的值含有 `create` 时匹配
type: z.literal('create'),
name: z.string(),
email: z.string().email(),
}),
z.object({
// 当 `type` 字段中的值含有 `update` 时匹配
type: z.literal('update'),
id: z.number(),
name: z.string(),
email: z.string().email(),
}),
]),
async handler(input) {
if (input.type === 'create') {
// input 为 { type: 'create', name: string, email: string }
} else {
// input 为 { type: 'update', id: number, name: string, email: string }
}
},
}),
};

类型:(error?: unknown | ActionError) => boolean

添加于: astro@4.15.0

isInputError() 函数常用于检查 ActionError 是否是输入验证错误。当 input 验证器是 z.object() 时,输入错误包括一个 fields 对象,其中错误消息按名称分组。

更多关于使用 isInputError() 的信息,请参见 表单输入错误指南

类型: (error?: unknown | ActionError) => boolean

添加于: astro@4.15.0

isActionError() 工具函数用于检查你的 action 是否引发了 handler 属性 中的 ActionError。这在缩小 try / catch 块中的泛型错误的类型时很有用。

添加于: astro@4.15.0

ActionError 构造函数常用于在 handler() 函数中抛出错误。它接受一个 code 属性,描述发生的错误(例如:"UNAUTHORIZED"),以及一个可选的 message 属性,提供进一步的细节。

添加于: astro@4.15.0

code 属性接受所有 HTTP 状态码的人类可读版本。以下是支持的 code:

  • BAD_REQUEST (400): 客户端发送了无效的输入。当 action input 验证器验证失败时会抛出此错误。
  • UNAUTHORIZED (401): 客户端缺乏有效的身份验证凭据。
  • FORBIDDEN (403): 客户端无权访问资源。
  • NOT_FOUND (404): 服务器找不到请求的资源。
  • METHOD_NOT_SUPPORTED (405): 服务器不支持请求的方法。
  • TIMEOUT (408): 服务器在处理请求时超时。
  • CONFLICT (409): 服务器无法更新资源,因为存在冲突。
  • PRECONDITION_FAILED (412): 服务器不满足请求的前提条件。
  • PAYLOAD_TOO_LARGE (413): 服务器无法处理请求,因为负载过大。
  • UNSUPPORTED_MEDIA_TYPE (415): 服务器不支持请求的媒体类型。注意:Actions 已经检查了 JSON 和表单请求的 Content-Type 标头,所以你可能不需要手动引发此代码。
  • UNPROCESSABLE_CONTENT (422): 服务器无法处理请求,因为存在语义错误。
  • TOO_MANY_REQUESTS (429): 服务器已超出指定的速率限制。
  • CLIENT_CLOSED_REQUEST (499): 客户端在服务器响应之前关闭了请求。
  • INTERNAL_SERVER_ERROR (500): 服务器意外失败。
  • NOT_IMPLEMENTED (501): 服务器不支持请求的功能。
  • BAD_GATEWAY (502): 服务器从上游服务器接收到无效响应。
  • SERVICE_UNAVAILABLE (503): 服务器暂时不可用。
  • GATEWAY_TIMEOUT (504): 服务器从上游服务器接收到超时。

添加于: astro@4.15.0

message 属性接受一个字符串。(例如:“用户必须登录。“)

类型: (context: APIContext) => ActionMiddlewareContext

添加于: astro@5.0.0

getActionContext() 是从你的中间件处理程序中调用的函数,用于检索有关入站 action 请求的信息。

此函数返回一个 action 对象,其中包含有关请求的信息,以及 setActionResult()serializeActionResult() 函数,用于以编程方式设置 Astro.getActionResult() 返回的值。

getActionContext() 运行你使用中间件以编程方式获取和设置 action 结果,允许你从 HTML 表单中持久化 action 结果,通过添加安全检查来限制 action 请求,等等。

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'form') {
const result = await action.handler();
setActionResult(action.name, serializeActionResult(result));
}
return next();
});

类型: { calledFrom: 'rpc' | 'form', name: string, handler: () => Promise<SafeResult<any, any>> } | undefined

action 是一个包含有关入站 action 请求的信息的对象。

它可以从 getActionContext() 中获取,并提供 action 名称、handler 以及 action 是否是从客户端 RPC 函数(例如 actions.newsletter())或 HTML 表单 action 中调用的。

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'rpc' && action.name.startsWith('private')) {
// 检查是否有有效的会话令牌
}
// ...
});

类型: (actionName: string, actionResult: SerializedActionResult) => void

setActionResult() 是一个以编程方式设置中间件中 Astro.getActionResult() 返回值的函数。它接受 action 名称和由 serializeActionResult() 序列化的 action 结果。

当从 HTML 表单中调用 action 以持久化和加载结果时,这很有用。

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action?.calledFrom === 'form') {
const result = await action.handler();
// ... 处理 action 结果
setActionResult(action.name, serializeActionResult(result));
}
return next();
});
请参阅 高级会话指南 以查看使用 Netlify Blob 的示例实现。

类型: (result: SafeResult<any, any>) => SerializedActionResult

serializeActionResult() 会将 action 结果序列化为 JSON 以进行持久化。这对于正确处理 MapDate 等非 JSON 返回值以及 ActionError 对象是必需的。

要把序列化后的 action 结果传递给 setActionResult() 时调用此函数:

src/middleware.ts
import { defineMiddleware } from 'astro:middleware';
import { getActionContext } from 'astro:actions';
export const onRequest = defineMiddleware(async (context, next) => {
const { action, setActionResult, serializeActionResult } = getActionContext(context);
if (action) {
const result = await action.handler();
setActionResult(action.name, serializeActionResult(result));
}
// ...
});

类型: (result: SerializedActionResult) => SafeResult<any, any>

deserializeActionResult() 将反转 serializeActionResult() 的效果,并将 action 结果返回到其原始状态。这对于访问序列化的 action 结果上的 dataerror 对象很有用。

类型: (action: ActionClient<any, any, any>) => string

添加于: astro@5.1.0

getActionPath() 工具方法接受一个 action 并返回一个 URL 路径,以便你可以直接将 action 调用作为 fetch() 操作执行。这允许你在调用 action 时提供诸如自定义标头之类的详细信息。然后,你可以根据需要 处理自定义格式化的返回数据,就像直接调用 action 一样。

下面的示例展示了如何调用一个定义的 like action,传递 Authorization 标头和 keepalive 选项:

src/components/my-component.astro
<script>
import { actions, getActionPath } from 'astro:actions'
await fetch(getActionPath(actions.like), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer YOUR_TOKEN'
},
body: JSON.stringify({ id: 'YOUR_ID' }),
keepalive: true
})
</script>

下面的示例展示了如何使用 sendBeacon API 调用相同的 like action:

src/components/my-component.astro
<script>
import { actions, getActionPath } from 'astro:actions'
navigator.sendBeacon(
getActionPath(actions.like),
new Blob([JSON.stringify({ id: 'YOUR_ID' })], {
type: 'application/json'
})
)
</script>
贡献 社区 赞助