前端开发
在 next-safe-action 中实现认证、授权…
为 next-safe-action 的 Server Action 编写中间件(认证、授权、日志、限流、错误拦截、上下文扩展、可复用中间件)时,按验证前后阶段正确选择 use() 与 useValidated() 并避免常见陷阱。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 next-safe-action 中通用
解决思路
- 用 createSafeActionClient() 创建基础客户端,再通过 .use() 添加中间件;.use() 可多次调用,每次返回新的客户端实例(链式不可变)。
- 理解执行顺序:中间件按添加顺序自上而下执行(before 部分),结果自下而上回传(after 部分),形成洋葱模型。
- 通过 next({ ctx }) 向下传递上下文,每一层的 ctx 会与上一层深合并(deep-merge),最终在 .action() 中拿到累积后的 ctx。
- use() 中间件函数签名接收 { clientInput, bindArgsClientInputs, ctx, metadata, next },可在调用 next 时扩展 ctx。
- 默认使用 .use() 处理认证、日志、限流等无需验证输入的逻辑,以及需要访问原始 clientInput 的场景。
- 仅在中间件逻辑依赖已验证输入时使用 .useValidated(),它运行在输入验证之后,可拿到带类型的 parsedInput。
- useValidated() 中间件函数签名接收 { parsedInput, clientInput, bindArgsParsedInputs, bindArgsClientInputs, ctx, metadata, next }。
- 遵守链式规则:必须在 .useValidated() 之前调用 .inputSchema() 或 .bindArgsSchemas();不能在 .useValidated() 之后调用 .inputSchema()/.bindArgsSchemas();不能在 .useValidated() 之后调用 .use();可链式调用多个 .useValidated()。
- 注意 schema transform:useValidated() 中的 parsedInput 是转换后的值,clientInput 保留原始值。
- 在 onError/onSettled 回调中:use() 设置的 ctx 始终可用;useValidated() 设置的 ctx 是可选的(可能为 undefined),因为验证失败时 useValidated() 不会执行。
- 始终 return next(...) 的结果,否则 action 会挂起。
- 在中间件中捕获错误时,先判断是否为框架错误(如 error instanceof Error && "digest" in error)并重新抛出,避免吞掉 Next.js 的 redirect/notFound 等错误,再处理其他错误。
- 使用 createMiddleware() 和 createValidatedMiddleware() 创建独立可复用的中间件。
- 参考配套文档:认证与授权模式、日志与监控中间件、独立可复用中间件。
- 执行顺序总览:use() 中间件(验证前)→ 输入验证(schema 解析)→ useValidated() 中间件(验证后)→ 服务端代码 .action()(接收最终 ctx 与 parsedInput)。
适用边界 · 注意事项
- 不要用 useValidated() 处理不需要验证输入的认证、日志、限流等逻辑,这些应使用 use()。
- 不要在 useValidated() 之前缺少 inputSchema/bindArgsSchemas,否则无法编译。
- 不要在中间件中捕获所有错误并返回统一错误对象,这会吞掉 redirect/notFound 等框架错误。