SvelteKit 远程函数初学者指南
你已经使用 +server.ts 端点和表单操作构建了 SvelteKit 应用。它们能正常工作,但你需要编写大量样板代码:解析请求体、手动验证输入,以及为客户端和服务器维护独立的类型定义。SvelteKit 远程函数提供了一种不同的方法——类型安全的服务器调用,无需传统 API 端点的繁琐流程。
本指南将解释什么是远程函数、何时使用每种类型,以及在采用它们之前应该了解的权衡取舍。
核心要点
- 远程函数将服务器端代码编译为 HTTP 端点,并自动生成 fetch 包装器,提供端到端的类型安全,无需手动维护 API 路由。
- 四种函数类型服务于不同目的:
query用于数据获取,form用于渐进增强的表单提交,command用于依赖 JavaScript 的变更操作,prerender用于构建时的静态数据。 - 每个远程函数都会成为公开可访问的端点,因此使用 Zod 或 Valibot 等 Standard Schema 库进行输入验证对安全至关重要。
- 远程函数需要显式启用且仍处于实验阶段,因此预期会有 API 变更,请保持 SvelteKit 更新以解决潜在的安全漏洞。
什么是 SvelteKit 远程函数?
远程函数让你编写服务器端代码,客户端可以像调用普通函数一样调用它们。在幕后,SvelteKit 将这些函数编译为 HTTP 端点,并为客户端生成 fetch 包装器。你可以获得端到端的类型安全,而无需构建或维护传统的 API 路由。
可以把它理解为 SvelteKit 处理前端和后端之间的管道工作。你在 .remote.ts 文件中编写函数,SvelteKit 负责序列化、端点生成和类型推断。
如果你想查看官方参考文档,该功能在 SvelteKit 文档的远程函数部分有详细说明: https://kit.svelte.dev/docs/remote-functions
启用实验性功能
远程函数需要在 svelte.config.js 中通过 kit.experimental.remoteFunctions 显式启用:
const config = {
kit: {
experimental: {
remoteFunctions: true
}
}
};
export default config;
如果你想在 Svelte 组件中直接使用 await,还需要单独启用 Svelte 的实验性异步支持。这不是必需的——远程函数在没有它的情况下也能工作——但它能简化组件代码。
SvelteKit 服务器函数的四种类型
远程函数有四种类型,每种都为特定用例设计。
Query:获取动态数据
当从数据库、API 或任何服务器资源读取数据时使用 query。查询可以在组件渲染期间运行,并在同一渲染生命周期内进行去重和批处理。
import { query } from '$app/server';
import { db } from '$lib/db';
import { posts } from '$lib/schema';
export const getPosts = query(async () => {
return await db.select().from(posts);
});
对于性能关键场景,query.batch 将多个同时发生的调用组合成单个请求——无需手动优化即可解决 n+1 问题。
Form:具有渐进增强的数据变更
form 函数处理用户输入提交。它的关键优势是渐进增强。表单在没有 JavaScript 的情况下也能工作,在需要时回退到传统提交方式。
将返回的对象展开到你的 <form> 元素上,SvelteKit 会自动处理增强和非增强提交。
Command:灵活的变更操作
command 的工作方式类似 form,但不绑定到表单元素。用于按钮点击、拖放操作或任何在表单上下文之外触发的变更操作。
与表单不同,命令需要 JavaScript。当渐进增强很重要时选择 form。当需要灵活性时选择 command。
Prerender:构建时的静态数据
prerender 在构建期间获取数据,而不是在运行时。结果在构建时缓存,并通过平台缓存或 CDN 提供服务。用于配置、仅在部署时更改的 CMS 内容,或任何不需要实时更新的数据。
重要限制:你不能在完全预渲染的页面上使用 query,因为查询本质上是动态的。
Discover how at OpenReplay.com.
安全性:每个远程函数都是公开端点
这一点至关重要:每个远程函数都会成为任何人都可以调用的 HTTP 端点。输入验证不是可选的——它是必需的。
SvelteKit 期望你使用 Zod 或 Valibot 等 Standard Schema 库验证参数(“Standard Schema”倡议的文档位于 https://standardschema.dev):
import { query } from '$app/server';
import * as v from 'valibot';
import { db } from '$lib/db';
import { posts } from '$lib/schema';
const Params = v.object({
slug: v.string()
});
export const getPost = query(Params, async ({ slug }) => {
return await db.select().from(posts).where(eq(posts.slug, slug));
});
没有验证,攻击者可以向你的端点发送任意数据。SvelteKit 通常对验证失败返回 400 级错误,避免信息泄露。
保持 SvelteKit 更新
过去的版本存在影响远程函数的安全漏洞,包括 DoS 问题。保持版本更新,特别是在该功能仍处于实验阶段时(截至 SvelteKit 2.x)。
需要考虑的权衡
远程函数减少了样板代码,但并非魔法。考虑这些限制:
- 文件位置很重要:
.remote.ts文件可以放在src中的任何位置,除了src/lib/server - 预渲染缓存:浏览器和 CDN 缓存意味着数据在重新部署之前会保持陈旧
- 实验性状态:API 可能会变更,预期会有 bug
当你想要类型安全的客户端-服务器通信而不维护独立的端点定义时,远程函数效果最好。它们不是每个 +server.ts 文件的替代品——复杂的身份验证流程或第三方 webhook 处理程序可能仍然需要传统端点。
何时使用每种函数类型
| 场景 | 函数类型 |
|---|---|
| 获取数据库记录 | query |
| 带回退的表单提交 | form |
| 按钮触发的操作 | command |
| CMS 内容、站点配置 | prerender |
结论
SvelteKit 远程函数简化了客户端和服务器代码之间的边界。它们消除了手动端点维护,同时提供内置验证和类型安全。从 query 开始进行数据获取,添加 form 处理用户输入,当这些特定模式符合你的需求时使用 command 或 prerender。
该功能是实验性的——预期会有变更。但对于厌倦了端点样板代码的 SvelteKit 开发者来说,远程函数提供了一个值得探索的引人注目的替代方案。
常见问题
可以,远程函数和传统端点可以无冲突地共存。你可以逐步迁移,一次转换一个端点。许多项目将复杂的身份验证或 webhook 处理程序保留为传统端点,同时对更简单的数据操作使用远程函数。
远程函数不包含内置的身份验证。你通过 SvelteKit 的标准机制访问请求上下文,并在每个函数内实现授权检查。在任何需要保护的函数开始时验证用户会话和权限,就像使用传统端点一样。
未处理的错误会向客户端返回 500 响应。SvelteKit 在生产环境中会清理错误消息以防止泄露敏感信息。对于受控的错误处理,从 @sveltejs/kit 抛出 redirect 或 error 对象,SvelteKit 会在客户端适当地处理它们。
远程函数适用于任何支持服务器端渲染的适配器。它们编译为标准的 HTTP 端点,因此 Vercel、Netlify 和 Cloudflare Workers 等平台可以正常处理它们。预渲染函数在任何地方都能工作,因为它们仅在构建时执行。
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.