Meteor methods 是 Meteor 框架中用于从客户端调用服务端数据变更的原语。在 Meteor 3 中,服务端方法为异步执行;延迟补偿(latency compensation)仍通过客户端 stub 生效。本技能适用于编写或调试 Meteor methods(Meteor.methods、Meteor.call、Meteor.callAsync),触发场景包括使用 check() 进行参数校验、乐观 UI 等。
用途与决策流程
当代码需要变更服务端数据时,应使用 method。若客户端需要在服务端回复前读取结果,可编写同名客户端 stub:它先变更本地 Minimongo 集合,若服务端结果不一致则回滚该变更。若方法接受不可信输入,必须用 check() 校验每个参数,否则应拒绝编写该方法。若方法对速率敏感,应添加 DDPRateLimiter.addRule。
主要能力与代码骨架
服务端方法骨架示例:
import { Meteor } from "meteor/meteor"; import { check, Match } from "meteor/check";
Meteor.methods({ async addItem(payload) { check(payload, { title: String, qty: Match.Integer, }); if (!this.userId) { throw new Meteor.Error("not-authorized"); } const _id = await Items.insertAsync({ ...payload, ownerId: this.userId, createdAt: new Date(), }); return _id; }, });
客户端调用示例:
try { const id = await Meteor.callAsync("addItem", { title: "Hi", qty: 1 }); setLocalId(id); } catch (err) { if (err && typeof err === "object" && "error" in err) { console.error(err.error, err.reason, err.details); } else { console.error("local or transport failure", err); } }
乐观 UI
在客户端定义同名方法。客户端 stub 立即针对本地 Minimongo 运行;服务端的权威结果会回滚任何不一致。示例:
// client/methods.js import { Meteor } from "meteor/meteor"; import { Random } from "meteor/random"; Meteor.methods({ addItem(payload) { Items.insert({ ...payload, _id: Random.id(), ownerId: Meteor.userId(), createdAt: new Date(), }); }, });
当 stub 只需同步 Minimongo 时,同步 stub 最简单。callAsync 也支持异步 stub,适用于同一方法定义在客户端与服务端运行并使用 *Async 集合调用的场景。异步 stub 可以 await 基于微任务的本地工作,但不得等待 fetch、定时器、IndexedDB、worker 或其他浏览器宏任务 API。外部 I/O 应在 stub 之外运行。
速率限制
import { DDPRateLimiter } from "meteor/ddp-rate-limiter";
DDPRateLimiter.addRule( { type: "method", name: "addItem", userId: (userId) => Boolean(userId), }, 5, // operations 10000, // per 10s );
Meteor 3.5+ 允许使用异步匹配函数进行基于数据库的决策。在 Meteor 3.0 至 3.4 中,匹配函数必须保持同步;应使用固定规则、预计算的同步状态,或升级版本,而不是在匹配函数中 await Mongo。Meteor 会在传入连接的消息队列上顺序 await 异步匹配函数。应只投影所需字段并保持查询快速。被拒绝的匹配函数 Promise 会使该次调用报错;应显式测试该路径。规则对象 schema 以及按连接与按用户键的说明见 references/rate-limiting.md。
错误处理
对于有意向客户端暴露的失败,抛出 Meteor.Error(code, reason, details?)。普通 Error 会在服务端记录日志,并对客户端净化为 Meteor.Error(500, "Internal server error");其原始消息与堆栈不会暴露。Meteor.Error 携带 code、reason 与 details。不要假设每个 callAsync 拒绝都具有该形状:回调误用、传输失败与本地 stub 异常可能产生原生或任意错误。在读取 Meteor 特定字段前应先收窄捕获值。
反模式
方法未对每个参数使用 check():应在代码审查中拒绝该方法。将同一方法同时用于已认证与未认证调用:应拆分为两个方法。在客户端 stub 中 await 浏览器宏任务 API(如 fetch 或定时器):异步 stub 是有效的,但这些 API 会让无关代码在乐观模拟完成前运行。在异步方法体内调用 Meteor.user():应使用 this.userId。
参见
references/check-and-validate.md references/rate-limiting.md references/eval-cases.md