2
  • 我正在构建一个“TODO”应用程序,它使用服务人员缓存请求的响应,并且在用户处于脱机状态时,缓存的数据将显示给用户。
  • 服务器公开了一个REST-ful端点,该端点具有针对资源公开的POST,PUT,DELETE和GET端点。
  • 考虑到当用户离线并提交TODO项目时,我将其保存到本地IndexedDB,但由于没有网络连接,所以无法发送此POST请求。同样是对于PUT真实,删除请求,其中用户更新或删除现有的TODO项目

问题在离线优先应用程序的情况下,如何将数据与远程数据库同步?

  • 在使用同步与待处理的请求是什么模式的REST-FUL服务器何时连接重新联机?

回答

4

目前我可以想到两种方法,它取决于您在后端使用的存储选项。

如果您使用的是RDBMS备份所有数据:

用这种方法下线第一系统的问题是在发布新数据或更新现有数据时,你可能会面临冲突的可能性。

作为避免冲突发生的第一个措施,您将不得不为您的客户端中的所有对象生成唯一的ID,并以这种方式在发布到服务器上并保存在数据库中时保持唯一。为此,您可以安全地依靠UUIDs来生成对象的唯一ID。 UUID保证了分布式系统中各个系统之间的唯一性,并且取决于您的实现语言,您将拥有无任何麻烦地生成UUID的方法。

设计您的本地数据库,以便您可以在本地数据库中使用UUID作为主键。在服务器端,可以同时使用自动递增和索引的整数类型,主键和VARCHAR类型来保存UUID。服务器上的主键唯一标识该表中的对象,而UUID在表和数据库中唯一标识记录。

因此,在同步时将对象发布到服务器时,您只需检查是否存在具有UDID的任何对象并从中采取相应的操作。当您从服务器获取对象时,请从您的表中发送对象的主键和对象的UDID。这就是为什么当您在模型对象中序列化响应或将它们保存在本地数据库中时,您可以告诉已经同步的对象,而不是因为需要同步的对象在本地数据库中没有主键, UUID。

当您的服务器出现故障并且在同步时拒绝保存数据时,可能会出现这种情况。在这种情况下,您可以在对象中保留一个整数变量,以保持您尝试同步它的次数。如果此数字超过某个值(例如3),则继续同步下一个对象。现在,您对未识别的对象所做的工作就是您对这些对象的策略,作为一种解决方案,您可以丢弃它们或仅保留在本地。

如果你不使用RDBMS

作为一种替代方法,而不是使所有的对象,你可以保持每个客户端本地执行的服务器事务。每个客户端只同步事务,并且通过从下往上处理所有事务来获取当前状态。这与Git使用的非常相似。它以交易形式(比如已添加(或删除)以及由谁交易)的形式将更改保存在存储库中。每个用户的存储库的当前状态都是从事务处理的。这种方法不会导致冲突,但你可以看到它的开发有点棘手。

+0

谢谢ANKUR的解释,感谢你在它花费的时间。我们计划使用MySQL('RDBMS')作为这个项目的数据库。 – daydreamer

0

当连接重新联机时,使用哪些模式将挂起的请求与REST-ful Server同步?

Background Sync API将适用于此场景。它使Web应用程序能够在后台同步数据。有了这个,它可以推迟行动,直到用户有可靠的连接,确保用户想要发送的任何内容实际上都被发送。即使用户浏览或关闭浏览器,也会执行操作,并且您可以根据需要通知用户。

既然你保存到INDEXDB,你可以注册一个同步事件,当用户添加,删除或更新TODO项目

function addTodo(todo) { 
    return addToIndeDB(todo).then(() => { 
    // Wait for the scoped service worker registration to get a 
    // service worker with an active state 
    return navigator.serviceWorker.ready; 
    }).then(reg => { 
    return reg.sync.register('add-todo'); 
    }).then(() => { 
    console.log('Sync registered!'); 
    }).catch(() => { 
    console.log('Sync registration failed :('); 
    }); 
} 

您已经注册add-todo类型你”的同步事件我们将在服务人员中监听,然后当您收到此事件时,您将从IndexDB中检索数据并对您的Restful API执行POST。

self.addEventListener('sync', event => { 
if (event.tag == 'add-todo') { 
     event.waitUntil(
     getTodo().then(todos => { 
     // Post the messages to the server 
     return fetch('/add', { 
      method: 'POST', 
      body: JSON.stringify(todos), 
      headers: { 'Content-Type': 'application/json' } 
     }).then(() => { 
      // Success! 
     }); 
     }) 
     }) 
    ); 
    } 
}); 

这只是你怎么可以使用后台同步实现它的一个例子。请注意,您必须在服务器上处理冲突解决方案。

您可以在客户端和服务器上的Couchbase或CouchDB上使用PouchDB。通过客户端上的PouchDB,您可以将数据保存到客户端,并将其设置为在用户联机时自动同步/复制数据。当数据库同步并且存在冲突的更改时,CouchDB将检测到这一点并将用特殊属性"_conflicts":true来标记受影响的文档。它决定它将使用哪一个作为最新修订版本,并将其他文件另存为该记录的前一版本。它不会尝试合并冲突版本。由您决定如何在您的应用程序中完成合并。它和Couchbase没有太大的区别。有关冲突解决的更多信息,请参阅下面的链接。

我用pouchDB和couchbase/CouchDB的/ IBM cloudant,但我已经做了,通过Hoodie它具有用户认证出来盒子,处理冲突管理等等。把它想象成你的后端。在您的TODO应用程序中,连帽衫将非常适合。我写了关于如何使用帽衫,请参阅以下链接的内容:

相关问题