diff --git a/src/content/docs/zh-cn/guides/actions.mdx b/src/content/docs/zh-cn/guides/actions.mdx index daf8f8b96c1a0..6c5cac90040d5 100644 --- a/src/content/docs/zh-cn/guides/actions.mdx +++ b/src/content/docs/zh-cn/guides/actions.mdx @@ -24,7 +24,7 @@ Actions 是在 `src/actions/index.ts` 中导出的 `server` 对象中定义的 ```ts title="src/actions/index.ts" import { defineAction } from 'astro:actions'; -import { z } from 'astro:schema'; +import { z } from 'astro/zod'; export const server = { myAction: defineAction({ /* ... */ }) @@ -62,22 +62,22 @@ async () => { } ``` -2. 导入 `astro:actions` 中的 `defineAction()` 工具以及 `astro:schema` 中的 `z` 对象。 +2. 导入 `astro:actions` 中的 `defineAction()` 工具以及 `astro/zod` 中的 `z` 对象。 ```ts ins={1-2} title="src/actions/index.ts" import { defineAction } from 'astro:actions'; - import { z } from 'astro:schema'; + import { z } from 'astro/zod'; export const server = { // action 声明 } ``` -3. 使用 `defineAction()` 工具定义一个 `getGreeting` action。`input` 属性将使用 [Zod](https://zod.dev) scheme 验证输入参数,`handler()` 函数包含要在服务器上运行的后端逻辑。 +3. 使用 `defineAction()` 工具定义一个 `getGreeting` action。`input` 属性将使用 [Zod schema](/zh-cn/reference/modules/astro-zod/#common-data-type-validators) scheme 验证输入参数,`handler()` 函数包含要在服务器上运行的后端逻辑。 ```ts ins={5-12} title="src/actions/index.ts" import { defineAction } from 'astro:actions'; - import { z } from 'astro:schema'; + import { z } from 'astro/zod'; export const server = { getGreeting: defineAction({ @@ -206,13 +206,13 @@ const updatedLikes = await actions.likePost.orThrow({ postId: 'example' }); #### 创建一个 `ActionError` -为了抛出一个错误,从 `astro:actions` 模块中导入 `ActionError()` 类。传递一个人类可读的状态 `code`(例如 `"NOT_FOUND"` 或 `"BAD_REQUEST"`),以及一个可选的 `message` 以提供有关错误的更多信息。 +为了抛出一个错误,从 `astro:actions` 模块中导入 [`ActionError()` 类](/zh-cn/reference/modules/astro-actions/#actionerror)。传递一个人类可读的状态 `code`(例如 `"NOT_FOUND"` 或 `"BAD_REQUEST"`),以及一个可选的 `message` 以提供有关错误的更多信息。 当用户并未登录,且在检查了假设的 “use-session” cookie 进行身份验证后,这个例子从 `likePost` action 抛出一个错误: ```ts title="src/actions/index.ts" ins=/ActionError(?= )/ ins={9-12} import { defineAction, ActionError } from "astro:actions"; -import { z } from "astro:schema"; +import { z } from "astro/zod"; export const server = { likePost: defineAction({ @@ -289,7 +289,7 @@ Actions 默认接受 JSON 数据。要接受来自 HTML 表单的表单数据, ```ts title="src/actions/index.ts" ins={6} import { defineAction } from 'astro:actions'; -import { z } from 'astro:schema'; +import { z } from 'astro/zod'; export const server = { comment: defineAction({ @@ -300,6 +300,55 @@ export const server = { } ``` +### 在表单输入中使用验证器 + +当你的 action [配置为接受表单数据](/zh-cn/reference/modules/astro-actions/#accept-属性) 时,你可以使用任何 Zod 验证器来验证字段(例如用于日期输入的 `z.coerce.date()`)。在 `z.object()` 验证器上也支持扩展函数,包括 `.refine()`、`.transform()` 和 `.pipe()`。 + +此外,Astro 在底层为你提供了特殊处理,以便方便地验证以下类型的字段输入: + +- 使用 `z.number()` 验证类型为 `number` 的输入 +- 使用 `z.coerce.boolean()` 验证类型为 `checkbox` 的输入 +- 使用 `z.instanceof(File)` 验证类型为 `file` 的输入 +- 使用 `z.array(/* validator */)` 验证相同 `name` 的多个输入 +- 使用 `z.string()` 验证所有其他输入 + +当你的表单提交时若包含空输入,输出类型可能与你的 `input` 校验器不匹配。空值会被转换为 `null`,但在验证数组或布尔值时除外。例如,如果一个类型为 `text` 的输入以空值提交,结果将是 `null`,而不是空字符串(`""`)。 + +要应用不同验证器的并集,请使用 `z.discriminatedUnion()` 包装器,根据特定表单字段缩小类型。此示例接受 “create” 或 “update” 用户的表单提交,使用名称为 `type` 的表单字段来确定应针对哪个对象进行验证: + +```ts title="src/actions/index.ts" {7-21} "create" "update" +import { defineAction } from 'astro:actions'; +import { z } from 'astro/zod'; + +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') { + // 输入为 { type: 'create', name: string, email: string } + } else { + // 输入为 { type: 'update', id: number, name: string, email: string } + } + }, + }), +}; +``` + ### 校验表单数据 Actions 将解析提交的表单数据为一个对象,使用每个输入的 `name` 属性的值作为对象键。例如,包含 `` 的表单将被解析为一个对象,如 `{ search: 'user input' }`。你的 action 的 `input` 模式将用于验证此对象。 @@ -328,7 +377,7 @@ Actions 将解析提交的表单数据为一个对象,使用每个输入的 `n ```ts title="src/actions/index.ts" ins={5-12} import { defineAction } from 'astro:actions'; - import { z } from 'astro:schema'; + import { z } from 'astro/zod'; export const server = { newsletter: defineAction({ @@ -442,7 +491,7 @@ import { actions } from 'astro:actions'; ```ts title="src/actions/index.ts" mark={10} import { defineAction } from 'astro:actions'; -import { z } from 'astro:schema'; +import { z } from 'astro/zod'; export const server = { createProduct: defineAction({ @@ -655,7 +704,7 @@ export const onRequest = defineMiddleware(async (context, next) => { 要授权 action 请求,请在 action handler 中添加身份验证检查。你可能希望使用 [身份验证库](/zh-cn/guides/authentication/) 来处理会话管理和用户信息。 -Action 公开完整的 APIContext 对象,以访问从中间件传递的属性,使用 `context.locals`。当用户未经授权时,你可以使用 `UNAUTHORIZED` 代码引发 `ActionError`: +Action 公开 [`APIContext` 对象的一个子集](/zh-cn/reference/modules/astro-actions/#actionapicontext),以访问从中间件传递的属性,使用 `context.locals`。当用户未经授权时,你可以使用 `UNAUTHORIZED` 代码引发 `ActionError`: ```ts title="src/actions/index.ts" {6-8} import { defineAction, ActionError } from 'astro:actions'; @@ -678,7 +727,7 @@ export const server = { Astro 建议从 action handler 中授权用户会话,以遵从每个 action 的权限级别和速率限制。但是,你也可以从中间件中拦截所有 action 请求(或一组 action 请求)。 -使用 `getActionContext()` 函数从你的中间件中检索有关任何传入 action 请求的信息。这包括 action 名称以及该 action 是否是使用客户端远程过程调用(RPC)函数(例如 `actions.blog.like()`)或 HTML 表单调用的。 +使用 [`getActionContext()` 函数](/zh-cn/reference/modules/astro-actions/#getactioncontext) 从你的中间件中检索有关任何传入 action 请求的信息。这包括 action 名称以及该 action 是否是使用客户端远程过程调用(RPC)函数(例如 `actions.blog.like()`)或 HTML 表单调用的。 以下示例拒绝所有没有有效会话令牌的 action 请求。如果检查失败,将返回一个 “Forbidden” 响应。注意:此方法确保只有在会话存在时才能访问 action,但不是安全授权的替代品。 diff --git a/src/content/docs/zh-cn/reference/modules/astro-actions.mdx b/src/content/docs/zh-cn/reference/modules/astro-actions.mdx index c14e9f065cf4d..447adfb66f1e6 100644 --- a/src/content/docs/zh-cn/reference/modules/astro-actions.mdx +++ b/src/content/docs/zh-cn/reference/modules/astro-actions.mdx @@ -19,26 +19,33 @@ Action 帮助你构建一个类型安全的后端,你可以从客户端代码 ## 从 `astro:actions` 导入 ```js -import { +import { + ACTION_QUERY_PARAMS, + ActionError, actions, defineAction, - isInputError, + getActionContext, + getActionPath, isActionError, - ActionError, + isInputError, } from 'astro:actions'; ``` ### `defineAction()`

- + +**类型:** (\{ accept, input, handler \}) => ActionClient

-`defineAction()` 函数接受一个 [`handler()`](#handler-属性) 函数,其中包含在调用 Action 时要运行的服务器逻辑,以及一个可选的 [`input`](#input-验证器) 属性,用于在运行时验证输入参数。 +一个用于在 `src/actions/index.ts` 中定义新的 actions 的工具函数。它接受一个 [`handler()`](#handler-属性) 函数,其中包含在调用 Action 时要运行的服务器逻辑,以及一个可选的 [`input`](#input-验证器) 属性,用于在运行时验证输入参数。 + +```ts title="src/actions/index.ts" +import { defineAction } from 'astro:actions'; +import { z } from 'astro/zod'; -```ts export const server = { - getGreeting: defineAction({ + getGreeting: defineAction({ input: z.object({ name: z.string(), }), @@ -53,12 +60,12 @@ export const server = {

-**类型:**`(input, context) => any` +**类型:**(input: TInputSchema, context: ActionAPIContext) => TOutput | Promise\

-`defineAction()` 函数接受一个 `handler()` 函数,其中包含在调用 Action 时要运行的服务器逻辑。此函数可以返回数据,这些数据将自动序列化并发送给调用者。 +一个必要的函数,其中包含在调用 Action 时要运行的服务器逻辑。`handler()` 函数返回的数据将自动序列化并发送给调用者。 -`handler()` 函数被调用时,接受用户输入作为其第一个参数。如果设置了 [`input`](#input-验证器) 验证器,那么用户输入将在传递给 `handler()` 前进行验证。第二个参数是一个 `context` 对象,包含大多数 Astro 的 [标准端点上下文](/zh-cn/reference/api-reference/),不包括 `getActionResult()`, `callAction()`, 和 `redirect()`。 +`handler()` 函数被调用时,接受用户输入作为其第一个参数。如果设置了 [`input`](#input-验证器) 验证器,那么用户输入将在传递给 `handler()` 前进行验证。第二个参数是 [Astro 的 `context` 对象的一个子集](#actionapicontext)。 返回值使用 [devalue 库](https://github.com/Rich-Harris/devalue) 进行解析。它支持 JSON 值,以及 `Date()`, `Map()`, `Set()`, 或 `URL()` 的实例。 @@ -69,66 +76,58 @@ export const server = { **类型:**`ZodType | undefined`

-可选的 `input` 属性接受一个 Zod 验证器(例如,Zod 对象,Zod 可区分联合),用于在运行时验证处理程序的输入。如果 action 验证失败,将返回 [`BAD_REQUEST` 错误](#actionerror) 并跳过 `handler`。 +一个可选的属性,接受一个 [Zod 验证器](/zh-cn/reference/modules/astro-zod/#common-data-type-validators)(例如,Zod 对象,Zod 可区分联合),用于在运行时验证处理程序的输入。如果 action 验证失败,将返回 [`BAD_REQUEST` 错误](#actionerror) 并跳过 `handler`。 如果省略 `input`,则 `handler` 将接收 JSON 请求的 `unknown` 类型的输入,以及表单请求的 `FormData` 类型。 -##### 与 `accept: 'form'` 一起使用 +#### `accept` 属性 -如果你的 action 接受表单输入,请使用 `z.object()` 验证器将表单数据自动解析为类型化对象。所有 Zod 验证器均支持表单数据字段(例如 `z.coerce.date()` )。为方便你验证以下类型的字段输入,Astro 在底层还提供了特殊处理: +

-- 使用 `z.number()` 验证类型为 `number` 的输入 -- 使用 `z.coerce.boolean()` 验证类型为 `checkbox` 的输入 -- 使用 `z.instanceof(File)` 验证类型为 `file` 的输入 -- 使用 `z.array(/* validator */)` 验证相同 `name` 的多个输入 -- 使用 `z.string()` 验证所有其他输入 +**类型:**`"form" | "json"`
+**默认值:**`json` +

-`z.object()` 验证器还支持包括 `.refine()`, `.transform()`, 和 `.pipe()` 在内的扩展函数。 +定义某个 action 所期望的格式: +* 当你的 action 接收 `Formdata` 时使用 `form`。 +* 在所有其他情况下,使用默认的 `json` -要搭配应用不同验证器的组合,请使用 `z.discriminatedUnion()` 包装器,它根据表单的特定字段以缩小类型范围。此示例通过接受表单提交以判断是 “创建(create)” 或是 “更新(update)” 了一名用户信息,判断时使用表单域的 `type` 属性字段来确定要验证的对象: +当你的 action 接受表单输入时,`z.object()` 验证器会自动将 `FormData` 解析为类型化对象。所有 Zod 验证器均受支持,可用于验证你的输入。 -```ts -import { defineAction } from 'astro:actions'; -import { z } from 'astro:schema'; +在 Actions 指南中 [了解如何将验证器与表单输入一起使用](/zh-cn/guides/actions/#在表单输入中使用验证器),包括示例用法和特殊输入处理。 -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 } - } - }, - }), -}; +### `actions` + +

+ +**类型:**Record\ActionClient\> +

+ +一个包含了你所有的 action 的对象,action 名称作为键,并关联到一个用于调用该 action 的函数。 + +```astro title="src/pages/index.astro" {5,8} +--- +--- + + ``` +为了让 Astro 识别此属性,你可能需要重启开发服务器或 [运行 astro sync 命令](/zh-cn/reference/cli-reference/#astro-sync)(`s + enter`车)。 + ### `isInputError()`

-**类型:**(error?: unknown | ActionError) => boolean
- +**类型:**`(error?: unknown) => boolean`

-`isInputError()` 函数常用于检查 `ActionError` 是否是输入验证错误。当 `input` 验证器是 `z.object()` 时,输入错误包括一个 `fields` 对象,其中错误消息按名称分组。 +一个常用于检查 [`ActionError`](#actionerror) 是否是输入验证错误的工具函数。当 `input` 验证器是 `z.object()` 时,输入错误包括一个 `fields` 对象,其中错误消息按名称分组。 更多关于使用 `isInputError()` 的信息,请参见 [表单输入错误指南](/zh-cn/guides/actions/#展示表单输入错误)。 @@ -138,66 +137,109 @@ export const server = {

-**类型:** (error?: unknown | ActionError) => boolean
- +**类型:**`(error?: unknown) => boolean`

-`isActionError()` 工具函数用于检查你的 action 是否引发了 [handler 属性](/zh-cn/reference/modules/astro-actions/#handler-属性) 中的 `ActionError`。这在缩小 `try / catch` 块中的泛型错误的类型时很有用。 +一个用于检查你的 action 是否引发了 [handler 属性](/zh-cn/reference/modules/astro-actions/#handler-属性) 中的 [`ActionError`](#actionerror) 的工具函数。这在缩小泛型错误的类型时很有用。 -### `ActionError` +```astro title="src/pages/index.astro" {9-12} "isActionError" +--- +--- -

- -

+ +``` + +### `ActionError` `ActionError` 构造函数常用于在 `handler()` 函数中抛出错误。它接受一个 `code` 属性,描述发生的错误(例如:`"UNAUTHORIZED"`),以及一个可选的 `message` 属性,提供进一步的细节。 +下面的示例在用户未登录时创建一个新的 `ActionError`: + +```ts title="src/actions/index.ts" {8-11} "ActionError" +import { defineAction, ActionError } from "astro:actions"; + +export const server = { + getUserOrThrow: defineAction({ + accept: 'form', + handler: async (_, { locals }) => { + if (locals.user?.name !== 'florian') { + throw new ActionError({ + code: 'UNAUTHORIZED', + message: 'Not logged in', + }); + } + return locals.user; + }, + }), +} +``` + + +你还可以使用 `ActionError` 在处理某个 action 的结果时缩小错误类型范围: + +```astro title="src/pages/index.astro" {9-12} "ActionError" +--- +--- + + +``` + #### `code`

- + +**类型:**ActionErrorCode

-`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` 标头](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/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): 服务器从上游服务器接收到超时。 +定义一个 [HTTP 状态码](#actionerrorcode) 的人类可读版本。 #### `message`

- + +**类型:** `string`

-`message` 属性接受一个字符串。(例如:"用户必须登录。") +一个用于描述错误的可选参数。(例如:"用户必须登录。") + +#### `stack` + +

+ +**类型:**`string` +

+ +用于传递堆栈跟踪的可选属性。 ### `getActionContext()`

-**类型:** `(context: APIContext) => ActionMiddlewareContext` +**类型:**(context: APIContext) => AstroActionContext

-`getActionContext()` 是从你的中间件处理程序中调用的函数,用于检索有关入站 action 请求的信息。 - -此函数返回一个 `action` 对象,其中包含有关请求的信息,以及 `setActionResult()` 和 `serializeActionResult()` 函数,用于以编程方式设置 `Astro.getActionResult()` 返回的值。 +一个从你的中间件处理程序中调用的函数,用于检索有关入站 action 请求的信息。此函数返回一个 `action` 对象,其中包含有关请求的信息,以及 `setActionResult()` 和 `serializeActionResult()` 函数,用于以编程方式设置 `Astro.getActionResult()` 返回的值。 `getActionContext()` 运行你使用中间件以编程方式获取和设置 action 结果,允许你从 HTML 表单中持久化 action 结果,通过添加安全检查来限制 action 请求,等等。 @@ -219,12 +261,10 @@ export const onRequest = defineMiddleware(async (context, next) => {

-**类型:** `{ calledFrom: 'rpc' | 'form', name: string, handler: () => Promise> } | undefined` +**类型:**\{ calledFrom: "rpc" | "form"; name: string; handler: () => Promise\<SafeResult\>; \} | undefined

-`action` 是一个包含有关入站 action 请求的信息的对象。 - - 它可以从 `getActionContext()` 中获取,并提供 action 名称、handler 以及 action 是否是从客户端 RPC 函数(例如 `actions.newsletter()`)或 HTML 表单 action 中调用的。 +一个包含有关入站 action 请求的信息的对象。它可以从 `getActionContext()` 中获取,并提供 action 名称、handler 以及 action 是否是从客户端 RPC 函数(例如 `actions.newsletter()`)或 HTML 表单 action 中调用的。 ```ts title="src/middleware.ts" {6} import { defineMiddleware } from 'astro:middleware'; @@ -239,6 +279,33 @@ export const onRequest = defineMiddleware(async (context, next) => { }); ``` +##### `calledFrom` + +

+ +**类型:**`"rpc" | "form"` +

+ +该 action 是通过 RPC 函数调用还是通过 HTML 表单的 action 调用。 + +##### `name` + +

+ +**类型:**`string` +

+ +action 的名称。用于在重定向期间跟踪 action 结果的来源。 + +##### `handler()` + +

+ +**类型:**() => Promise\<SafeResult\> +

+ +以编程方式调用一个 action 以获取结果。 + #### `setActionResult()`

@@ -246,7 +313,7 @@ export const onRequest = defineMiddleware(async (context, next) => { **类型:** `(actionName: string, actionResult: SerializedActionResult) => void`

-`setActionResult()` 是一个以编程方式设置中间件中 `Astro.getActionResult()` 返回值的函数。它接受 action 名称和由 [`serializeActionResult()`](#serializeactionresult) 序列化的 action 结果。 +一个以编程方式设置中间件中 `Astro.getActionResult()` 返回值的函数。它接受 action 名称和由 [`serializeActionResult()`](#serializeactionresult) 序列化的 action 结果。从中间件调用此函数将禁用 Astro 自身的 action 结果处理。 当从 HTML 表单中调用 action 以持久化和加载结果时,这很有用。 @@ -270,10 +337,10 @@ export const onRequest = defineMiddleware(async (context, next) => {

-**类型:** `(result: SafeResult) => SerializedActionResult` +**类型:**(res: SafeResult) => SerializedActionResult

-`serializeActionResult()` 会将 action 结果序列化为 JSON 以进行持久化。这对于正确处理 `Map` 或 `Date` 等非 JSON 返回值以及 `ActionError` 对象是必需的。 +将 action 结果序列化为 JSON 以进行持久化。这对于正确处理 `Map` 或 `Date` 等非 JSON 返回值以及 `ActionError` 对象是必需的。 要把序列化后的 action 结果传递给 `setActionResult()` 时调用此函数: @@ -295,20 +362,20 @@ export const onRequest = defineMiddleware(async (context, next) => {

-**类型:** `(result: SerializedActionResult) => SafeResult` +**类型:**(res: SerializedActionResult) => SafeResult

-`deserializeActionResult()` 将反转 `serializeActionResult()` 的效果,并将 action 结果返回到其原始状态。这对于访问序列化的 action 结果上的 `data` 和 `error` 对象很有用。 +反转 [`serializeActionResult()`](#serializeactionresult) 的效果,并将 action 结果返回到其原始状态。这对于访问序列化的 action 结果上的 `data` 和 `error` 对象很有用。 ### `getActionPath()`

-**类型:** `(action: ActionClient) => string` +**类型:**(action: ActionClient) => string

-`getActionPath()` 工具方法接受一个 action 并返回一个 URL 路径,以便你可以直接将 action 调用作为 `fetch()` 操作执行。这允许你在调用 action 时提供诸如自定义标头之类的详细信息。然后,你可以根据需要 [处理自定义格式化的返回数据](/zh-cn/guides/actions/#处理返回的数据),就像直接调用 action 一样。 +一个工具函数,接受一个 action 并返回一个 URL 路径,以便你可以直接将 action 调用作为 `fetch()` 操作执行。这允许你在调用 action 时提供诸如自定义标头之类的详细信息。然后,你可以根据需要 [处理自定义格式化的返回数据](/zh-cn/guides/actions/#处理返回的数据),就像直接调用 action 一样。 下面的示例展示了如何调用一个定义的 `like` action,传递 `Authorization` 标头和 [`keepalive`](https://developer.mozilla.org/en-US/docs/Web/API/Request/keepalive) 选项: @@ -342,3 +409,199 @@ navigator.sendBeacon( ) ``` + +### `ACTION_QUERY_PARAMS` + +

+ +**类型:**`{ actionName: string, actionPayload: string }` +

+ +一个包含 Astro 在处理表单 action 提交时内部使用的查询参数名称的对象。 + +当你使用 action 提交表单时,以下查询参数会被添加到 URL 中以跟踪该 action 调用: +* `actionName` - 包含正在调用的 action 名称的查询参数 +* `actionPayload` - 包含序列化表单数据的查询参数 + +当你需要在表单提交后清理 URL 时,此常量非常有用。例如,在重定向期间,你可能希望移除与 action 相关的查询参数: + +```ts title="src/pages/api/contact.ts" "ACTION_QUERY_PARAMS" +import type { APIRoute } from "astro"; +import { ACTION_QUERY_PARAMS } from 'astro:actions' + +export const GET: APIRoute = ({ params, request }) => { + const link = request.url.searchParams; + link.delete(ACTION_QUERY_PARAMS.actionName); + link.delete(ACTION_QUERY_PARAMS.actionPayload); + + return redirect(link, 303); +}; +``` + +## `astro:actions` 类型 + +```ts +import type { + ActionAPIContext, + ActionClient, + ActionErrorCode, + ActionInputSchema, + ActionReturnType, + SafeResult, + } from 'astro:actions'; +``` + +### `ActionAPIContext` + +[Astro 上下文对象](/zh-cn/reference/api-reference/) 的子集。以下属性不可用:`callAction`、`getActionResult`、`props` 和 `redirect`。 + +### `ActionClient` + +

+ +**类型:** +* (input?: any) => Promise\<SafeResult\> +* `{ queryString?: string; orThrow: (input?: any) => Promise>; }` +

+ +表示要在客户端调用的 action。你可以将其作为一个函数使用,该函数接收输入数据并返回一个包含 action 结果或验证错误的 [`SafeResult` 对象](#saferesult) 的 Promise。 + +下面的示例展示了在点赞计数增加失败时如何使用 `if` 语句提供错误处理: + +```astro title="src/pages/posts/post-1.astro" "data" "error" +--- +--- + + + + +``` + +或者,你可以将其作为一个对象来使用,以便访问 `queryString` 和另一个叫做 `orThrow()` 的方法。 + +#### `queryString` 属性 + +

+ +**类型:**`string` +

+ +可用于构建表单 action URL 的 action 的字符串表示。当你的表单组件在多个地方使用但提交时需要重定向到不同 URL 时,这会很有用。 + +下面的示例使用 `queryString` 构建一个 URL,该 URL 将通过自定义属性传递给表单的 `action` 属性: + +```astro title="src/pages/postal-service.astro" "queryString" +--- +import { actions } from 'astro:actions'; +import FeedbackForm from "../components/FeedbackForm.astro"; + +const feedbackUrl = new URL('/feedback', Astro.url); +feedbackUrl.search = actions.myAction.queryString; +--- + +``` + +#### `orThrow()` 属性 + +

+ +**类型:**`(input?: any) => Promise>` +

+ +一种在失败时抛出错误而不是返回错误的方法。当你更希望使用异常而不是错误处理时,这很有用。 + +下面的示例在递增点赞数失败时使用 `orThrow()` 来跳过错误处理: + +```astro title="src/pages/posts/post-1.astro" "orThrow" +--- +--- + + + + +``` + +### `ActionErrorCode` + +

+ +**类型:**`string` +

+ +[由 IANA 定义](https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml) 的一组标准 HTTP 状态代码的联合类型,使用可读的人类版本作为大写字符串并以下划线分隔(例如 `BAD_REQUEST` 或 `PAYLOAD_TOO_LARGE`)。 + +### `ActionInputSchema` + +

+ +**类型:**`ZodType` + +

+ +一种工具类型,它基于 Zod 模式自动推断某 action 作输入的 TypeScript 类型。这在你希望在自己的类型定义中将某个 action 的 [`input` 验证器类型](#input-验证器) 作为对象引用时非常有用。 + +当未提供 [`input` 验证器](#input-验证器) 时,返回 `never`。 + +下面的示例在名为 `contact` 的 action 上使用 `ActionInputSchema` 来: + +* 检索该 action 输入的 Zod 模式类型。 +* 检索该 action 验证器所期望的输入类型。 + +```astro title="src/components/Form.astro" {5} +--- +import { actions, ActionInputSchema } from 'astro:actions'; +import { z } from 'astro/zod'; + +type ContactSchema = ActionInputSchema; +type ContactInput = z.input; +--- +``` + +### `ActionReturnType` + +

+ +**类型:**Awaited\\> +

+ +一种工具类型,用于从 [action handler](#defineaction) 中提取输出类型。它会解包 Promise(如果处理器是异步的)和 `ReturnType`,以提供 [实际的输出类型](#saferesult)。如果你需要在自己的类型定义中引用某个 action 的输出类型,这会很有用。 + +下面的示例使用 `ActionReturnType` 来获取名为 `contact` 的 action 的预期输出类型: + +```astro title="src/components/Form.astro" {4} +--- +import { actions, ActionReturnType } from 'astro:actions'; + +type ContactResult = ActionReturnType; +--- +``` + +### `SafeResult` + +

+ +**类型:**`{ data: TOutput, error: undefined } | { data: undefined, error: ActionError }` +

+ +表示 action 调用的结果: +* 成功时,`data` 包含 action 的输出,`error` 是 `undefined`。 +* 失败时,`error` 包含一个 [`ActionError`](#actionerror),其中包含验证错误或运行时错误,`data` 是 `undefined`。