meteor-methods
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMeteor methods
Meteor 方法
Methods are Meteor's primitive for server-side mutation called from the client.
In Meteor 3 they are async on the server. Latency compensation still works via
client-side stubs.
方法是Meteor中用于从客户端调用服务端数据变更的基础组件。在Meteor 3中,服务端的方法是异步的。延迟补偿仍可通过客户端存根实现。
Decision flow
决策流程
- Is this code mutating server data? Use a method.
- Does the client need to read the result before the server replies? Write a client stub with the same name; it mutates the local Minimongo collection and the change is reverted if the server disagrees.
- Does the method accept untrusted input? Validate every argument with
. Otherwise the agent should refuse to write the method.
check() - Is the method rate-sensitive? Add a .
DDPRateLimiter.addRule
- 代码是否会修改服务端数据?使用方法。
- 客户端是否需要在服务端回复前读取结果?编写一个同名的客户端存根;它会修改本地Minimongo集合,若服务端返回不同结果,该变更会被回滚。
- 方法是否接受不可信输入?使用校验每个参数。否则应拒绝编写该方法。
check() - 方法是否对速率敏感?添加。
DDPRateLimiter.addRule
Scaffold
脚手架代码
javascript
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;
},
});javascript
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;
},
});Calling from the client
从客户端调用
javascript
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);
}
}javascript
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("本地或传输失败", err);
}
}Optimistic UI
乐观UI
Define the same method on the client. The client stub runs immediately against
the local Minimongo; the server's authoritative result reverts any divergence.
javascript
// 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(),
});
},
});Synchronous stubs are simplest when they only need synchronous Minimongo.
Async stubs are also supported by and are useful when the same
method definition runs on client and server with collection calls.
An async stub may await microtask-based local work, but it must not wait on
, timers, IndexedDB, workers, or other browser macrotask APIs. Run
external I/O outside the stub.
callAsync*Asyncfetch在客户端定义同名方法。客户端存根会立即针对本地Minimongo执行;服务端的权威结果会回滚所有不一致的变更。
javascript
// 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(),
});
},
});当存根仅需同步操作Minimongo时,同步存根是最简单的选择。也支持异步存根,当同一方法定义同时运行在客户端和服务端且使用集合调用时,异步存根会很有用。异步存根可以等待基于微任务的本地操作,但不能等待、定时器、IndexedDB、Worker或其他浏览器宏任务API。应在存根外部执行外部I/O操作。
callAsync*AsyncfetchRate limiting
速率限制
javascript
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+ permits async matcher functions for database-backed decisions. On
Meteor 3.0 through 3.4, matchers must stay synchronous; use a fixed rule,
precomputed synchronous state, or upgrade instead of awaiting Mongo in a
matcher.
Meteor awaits async matchers sequentially on the incoming connection's message
queue. Project only required fields and keep the lookup fast. A rejected
matcher Promise errors the invocation; test that path explicitly.
See for the rule-object schema and
per-connection vs per-user keys.
references/rate-limiting.mdjavascript
import { DDPRateLimiter } from "meteor/ddp-rate-limiter";
DDPRateLimiter.addRule(
{
type: "method",
name: "addItem",
userId: (userId) => Boolean(userId),
},
5, // 操作次数
10000, // 每10秒
);Meteor 3.5+允许使用异步匹配器函数来实现基于数据库的决策。在Meteor 3.0至3.4版本中,匹配器必须保持同步;请使用固定规则、预计算的同步状态,或者升级版本,不要在匹配器中等待Mongo操作。
Meteor会在传入连接的消息队列中按顺序等待异步匹配器完成。仅投影所需字段并保持查询速度。匹配器Promise拒绝会导致调用出错;请显式测试该路径。
有关规则对象的 schema 以及按连接 vs 按用户的限制键,请查看。
references/rate-limiting.mdError handling
错误处理
Throw for an intentional client-visible
failure. A plain is logged on the server and sanitized for the client
as ; its original message and
stack are not exposed. carries its code, reason, and details.
Do not assume every rejection has that shape: callback misuse,
transport failures, and local stub exceptions can produce native or arbitrary
errors. Narrow the caught value before reading Meteor-specific fields.
Meteor.Error(code, reason, details?)ErrorMeteor.Error(500, "Internal server error")Meteor.ErrorcallAsync对于需要让客户端可见的预期失败,抛出。普通的会在服务端记录日志,并在客户端被处理为;其原始消息和堆栈不会暴露给客户端。会携带错误码、原因和详细信息。不要假设每个的拒绝结果都是这种格式:回调误用、传输失败和本地存根异常都可能产生原生错误或任意错误。在读取Meteor特定字段前,请先缩小捕获值的范围。
Meteor.Error(code, reason, details?)ErrorMeteor.Error(500, "Internal server error")Meteor.ErrorcallAsyncAnti-patterns
反模式
- Methods without on every argument. Reject the method in code review.
check() - Reusing a method for both authenticated and unauthenticated calls. Split into two methods.
- Awaiting browser macrotask APIs such as or timers inside a client stub. Async stubs are valid, but those APIs let unrelated code run before the optimistic simulation finishes.
fetch - Calling inside an async method body. Use
Meteor.user().this.userId
- 未对每个参数使用的方法。在代码审查中拒绝此类方法。
check() - 同一个方法同时用于已认证和未认证调用。拆分为两个方法。
- 在客户端存根中等待浏览器宏任务API,如或定时器。异步存根本身是合法的,但这些API会让无关代码在乐观模拟完成前运行。
fetch - 在异步方法体内调用。请使用
Meteor.user()。this.userId
See also
另请参阅
references/check-and-validate.mdreferences/rate-limiting.mdreferences/eval-cases.md
references/check-and-validate.mdreferences/rate-limiting.mdreferences/eval-cases.md