Nodejs Meteor-DDP翻译

Nodejs Meteor-DDP翻译

DDP

DDP定义

DDP是一个客户端服务端之间的协议,他支持两种操作:

  • 客户端服务端发起远程过程调用
  • 客户端订阅数据,在他们变化时,服务器仍然保持向客户端发起通知。

本文定义了版本为"pre1"的DDP,以上仅仅是粗略的描述而非完整明确的定义。

一般消息结构

无论SockJS还是WebSocketsDDP都将使用较低级别的消息传输方式。(现在,你可以通过URL连接SockJS/sockjs以及WebSockets/websocket。后者很可能将改变为主应用URL指定的WebSocket子协议)

DDP消息就是指定了EJSON类型字段的JSON对象。每个消息都有一个msg字段来指定消息类型,或根据其他字段确定消息类型。

建立DDP连接

message分类

  1. connectclient → server
  • session : string (尝试连接到现有DDP会话)
  • version : string (拟定的协议版本)
  • support : [string] (客户端支持的协议版本,按优先顺序排列)
  1. connectedserver → client
  • session : string (DDP会话标识)
  1. failedserver → client
  • version : string (建议连接协议版本)

步骤

服务器可能会发送一个缺失键名为msg的初始化message,如果是这样的,客户端会忽略它,也不会等待此message。(此message是通过SockJS传输帮助实现代码热部署的,可能不应该,但目前我们是通过WebSocket实现的)

  • 客户端发送connect消息。
  • 如果服务器允许通信的消息的version与接收到的connect消息匹配,服务器会发送connected消息。
  • 否则服务器会关闭底层传输,发送failed消息,告之允许通信的DDP版本以及connect消息中的support字段。
  • 客户端建新connect消息尝试使用不同版本的DDP连接。客户端会发送众多的connect消息,直到连接匹配。如果服务器还不支持,就会忽略掉这些附加信息。

connect消息的support字段存储的版本信息是根据客户端的喜好优先级排列的。如果按照这个顺序,由客户端提出的version不是服务器支持的,服务器必会发送failed消息,强制客户端切换到更好的版本。

当客户端第一次连接到服务器,他会设置version为自己最认可的版本。如果有需要,客户端可以记住最终能与服务端匹配的版本。如果服务端能拥有更好的版本或者客户端已经升级,客户端始终依靠服务端发来的failed消息。

管理数据

message分类

  1. subclient → server
  • id : string (订阅的标识符)
  • name : string (订阅的名字)
  • params : [EJSON] (可选的订阅参数)
  1. unsubclient → server
  • id : stringsub消息中的id)
  1. nosubserver → client
  • id : stringsub消息中的id)
  1. error : Error(可选的错误,订阅错误总结或者订阅不存在等)
  2. addedserver → client
  • collection : stringCollecction名字)
  • id : stringDocumentid)
  • fields : EJSON (可选的EJSON值)
  1. changedserver → client
  • collection : stringCollecction名字)
  • id : stringDocumentid)
  • fields : EJSON (可选的EJSON值)
  • cleared : [string] (可选的,要删除的字段名)
  1. removedserver → client
  • collection : stringCollecction名字)
  • id : stringDocumentid)
  1. readyserver → client
  • subs : [string] (所有通过sub传递的id集)
  1. addedBeforeserver → client
  • collection : stringCollecction名字)
  • id : stringDocumentid)
  • fields : EJSON (可选的EJSON值)
  • before : string/nullDocument添加前的id,或者null表示添加完毕)
  1. movedBeforeserver → client
  • collection : stringCollecction名字)
  • id : stringDocumentid)
  • before : string/nullDocument删除前的id,或者null表示删除完毕)

步骤

  • 客户端指定感兴趣的信息集,发送sub消息给服务器
  • 在任何时间里,sub消息都会被通知到,服务器再发送数据到客户端。数据包含了addedchangedremoved消息。这些消息的本地数据模型将会被跟踪。
    • added消息表示了本地数据集的一个Documentid字段将被指定为Documentid,其他字段将被指定为Document的其他字段。minimongo通过特殊的方式将id转化为_id以存储到Mongo的文档集中。
    • changed消息表示了本地数据集的一个Document有了新的字段值或某些字段被删除了。id字段指定了被改变了的Documentidfields如果存在,表示文档中哪些字段值应该被替换。需要清除的字段应该放在cleared中以数组的形式呈现。
    • removed消息表示了本地数据集的一个Document需要删除了。id字段指定了需要删除的Documentid
  • 如果一个Collection被订购过,addedBefore消息可以取代added消息。包含有该idDocument在被添加后可插入before字段。如果before字段设置为null,Document将被添加,直到结束。对于一个给定的集合,服务器只应发送addedaddedBefore消息,而不是两者混合起来发。并且只能发送movedBefore消息给使用addedBefore消息的Collection

注意 : 被订购过的CollectionDDP消息没有使用在Meteor中,不过今后将会使用。

  • 客户端保持每一个Collection的数据。每个订阅不会做自己的数据集,但重复订阅会导致服务器发送关于Collection数据的字段联盟。例如,订阅器A说文档x有字段{foo:1,bar:2},订阅器B说文档x有{foo:1,baz:3},此时客户端将通知文档x拥有字段{foo:1,bar:2,baz:3}。如果字段值因为不同订阅器发生冲突,服务器会发送一个可用的字段值。
  • 当一个或多个订阅完成首批数据的发送,服务器将发送ready消息并伴随他们的id信息。

远程过程调用

message分类

  1. methodclient → server
  • method : string (方法名)
  • params : [EJSON] (可选的方法参数)
  • id : string (方法调用的客户端标识)
  1. resultserver → client
  • id : stringmethod消息中的id
  • error : Error (可选的,方法调用时的错误或者方法不存在)
  • result : EJSON (可选的,方法的返回值)
  1. updatedserver → client
  • methods : string (所有调用过method消息的id

步骤

  • 客户端发送一个method消息到服务器
  • 服务端响应一个result消息到客户端,带有方法调用的返回值或者错误信息。
  • 如果客户端接受过订阅,方法调用将直接影响数据。一旦服务端基于此方式完成所有相应数据的发送,服务器会发送一个updated消息给客户端,并带有所有方法的id集。

错误

resultnosub消息中会出现一个可选的error字段,一个错误消息具备如下字段:

  • error : number (错误号)
  • reason : string (可选的错误原因)
  • details : string (可选的错误详情)

error用来呈现订阅或者远程调用方法时出现的错误信息,订阅不存在或者调用方法不存在时,也通过这个传递信息。

客户端也能发送其他的错误消息给服务端,这样的消息将以error为最顶级直接呈现,并包含以下信息:

  • 不合法的JSON对象信息
  • 未知的msg类型
  • 其他畸形客户端请求(不包括所需字段)
  • 发送第一次connect消息或者connect消息初始化无关的其他内容

这样的error消息将包含以下字段

  • reason : string (描述错误的字符串)
  • offendingMessage : ** (包含原来解析正确的消息)

使用

做了两个例子,可以参照这篇文章做一下。

附录

EJSON是一种嵌入扩展JSONJSON对象。他支持所有平时所见的JSON类型,同时附加了如下内容:

Dates

{"$date": MILLISECONDS_SINCE_EPOCH}

Binary data:

{"$binary": BASE_64_STRING}

基于64位字符串,有符号+/,没有长度限制。

转义内容,否则看上去更像是EJSON类型:

{"$escape": THING}

例如,把JSON{$date:10000}装进EJSON对象中:

{"$escape": {"$date": 10000}}

注意:

转义内容的键必须存放在下级,你也可以再嵌套EJSON,例如,下面将$date映射到一个日期对象上:

{"$escape": {"$date": {"$date": 32491}}}

User-specified types

{"$type": TYPENAME, "$value": VALUE}

实现EJSON应尽量保证键位顺序。如果允许,也可以不必这样。

MongoDB依赖键位顺序。在MongoDB中使用EJSON是,实现的EJSON必须保持键位顺序。

有关EJSON的详细信息可以到Meteor文档中心-EJSON查阅,或是查看讲解EJSON的视频


3 回复

Node.js Meteor-DDP 翻译

DDP 定义

DDP客户端服务端 之间的一种 协议,它支持两种主要的操作:

  1. 客户端向服务端发起 远程过程调用
  2. 客户端订阅数据,当数据发生变化时,服务端持续向客户端发送更新。

本文档定义了 DDPpre1 版本,以上内容是对 DDP 的简要描述,而不是完整的定义。

一般消息结构

DDP 消息是具有 EJSON 类型字段的 JSON 对象。每个消息都包含一个 msg 字段,用于指定消息类型,或者根据其他字段确定消息类型。

建立 DDP 连接

客户端和服务器之间通过 connectconnectedfailed 消息进行连接。具体步骤如下:

  1. 客户端发送 connect 消息。
  2. 如果服务器支持客户端提议的 version,则发送 connected 消息。
  3. 否则,服务器会关闭连接并发送 failed 消息,指示支持的 DDP 版本。
// 示例代码:客户端发送 connect 消息
const ddpClient = new DDPClient({
    host: 'localhost',
    port: 3000,
    autoReconnect: true,
    autoReconnectTimer: 500,
    maintainCollections: true,
    retryOnError: false,
    useSockJS: true
});

ddpClient.connect((err) => {
    if (err) {
        console.error('Connection error:', err);
        return;
    }
    console.log('Connected to DDP server');
});

管理数据

DDP 通过 subunsubnosubaddedchangedremovedreadyaddedBeforemovedBefore 消息来管理数据。

  1. 客户端发送 sub 消息订阅数据。
  2. 服务器响应 addedchangedremoved 消息,更新客户端的数据。
  3. 当订阅完成,服务器发送 ready 消息。
// 示例代码:客户端订阅数据
ddpClient.subscribe('posts', [], (error) => {
    if (error) {
        console.error('Subscription error:', error);
    } else {
        console.log('Subscribed successfully');
    }
});

远程过程调用

DDP 支持远程过程调用,通过 methodresult 消息实现。

  1. 客户端发送 method 消息调用服务端方法。
  2. 服务端响应 result 消息,返回结果或错误信息。
// 示例代码:客户端调用服务端方法
ddpClient.call('addNumbers', [1, 2], (error, result) => {
    if (error) {
        console.error('Method call error:', error);
    } else {
        console.log('Result:', result);
    }
});

错误处理

DDP 中的错误信息可以通过 error 字段进行传递,包括错误号、原因和详情。

使用

为了更好地理解 DDP 的使用,可以参考 这篇文章

附录

EJSON 是一种扩展的 JSON 对象,支持日期、二进制数据和用户自定义类型。

// 示例代码:使用 EJSON
const date = new Date();
const ejsonDate = EJSON.newDate(date.getTime());
console.log(EJSON.stringify(ejsonDate)); // 输出 JSON 字符串

以上是 Node.js Meteor-DDP 的简要翻译和示例代码,希望对您有所帮助。


不错,顶~

DDP (Distributed Data Protocol) 是 Meteor 框架中用于客户端和服务端之间通信的一种协议。它支持两种主要的操作:远程过程调用(Remote Procedure Calls)和订阅数据变更通知。下面是针对 DDP 协议的一些核心概念及其示例代码的简要说明。

建立DDP连接

在 Node.js 中,我们可以使用 ddp 库来连接到 Meteor 服务端。下面是如何发送一个 connect 消息的例子:

const DDP = require('ddp');

let ddp = new DDP({
    host: 'localhost',
    port: 3000,
    autoReconnect: true,
    autoReconnectTimer: 500,
    maintainCollections: true,
    useSockJs: false
});

ddp.connect().then(() => {
    console.log('Connected to DDP server.');
}).catch((err) => {
    console.error(err);
});

订阅数据

客户端可以通过发送 sub 消息来订阅服务端上的数据。这里假设有一个名为 posts 的集合,我们将订阅其中的所有文档。

ddp.subscribe('posts', [], function() {
    let posts = ddp.collections.posts;
    if (posts) {
        console.log('Subscribed to posts:', posts);
    }
});

发起远程过程调用

客户端还可以向服务端发起远程过程调用。这里以调用一个名为 addPost 的方法为例:

ddp.call('addPost', ['Hello World'], function(error, result) {
    if (error) {
        console.error('Error in method call:', error);
    } else {
        console.log('Method result:', result);
    }
});

处理错误

无论是订阅还是方法调用,都可能产生错误。我们可以处理这些错误来确保程序的健壮性。

ddp.on('error', (error, handle) => {
    console.error('DDP Error:', error);
});

以上就是对 Node.js Meteor-DDP 的简要介绍及示例代码。通过这些基本的操作,你可以在客户端和服务端之间实现高效的数据同步和方法调用。

回到顶部