Firebase数据库:如果客户端处于脱机状态,显然规则不适用?

时间:2017-03-17 14:46:53

标签: android firebase firebase-realtime-database firebase-security

考虑以下示例:

我在test/节点上写了一个值,并且我已经设置了一个允许写入的规则,只有当"(新值)等于(旧值+) 1)",即newData.val() == data.val() + 1

我们假设test/节点的初始值为0

如果客户端离线并执行以下命令:

testRef.setValue(1);
testRef.setValue(2);
testRef.setValue(3);
testRef.setValue(4);
testRef.setValue(5);

然后,当他重新上线时,价值5将写入数据库,但我不确定我理解为什么,因为5 != 0 + 1。我想这是由于本地数据库中先前值的缓存而发生的,但不幸的是,这不是我想要实现的结果。我希望服务器拒绝该值,因为它不遵循数据库的规则。

有没有办法实现这个目标?

或者是否还有其他解决方法,以便我可以实现以下内容:

testRef.setValue(1); - &gt; 将值写入本地数据库 - &gt; 检查值是否遵循在线数据库的规则 - &gt; < / strong>如果值不符合规则,或者我们无法检查,因为我们处于脱机状态,则从本地数据库中删除该值

1 个答案:

答案 0 :(得分:1)

我认为对于您的问题,“离线”意味着客户端没有连接。在我的测试中,我通过启用飞行模式来模拟它。

user guide中介绍了Firebase脱机功能。那里提供的一个对您的问题很重要的细节是:

  

Firebase实时数据库客户端自动保留队列   应用程序脱机时执行的所有写入操作...   当应用程序重新获得连接时,将发送所有操作   Firebase实时数据库服务器。

您可以使用下面的代码查看此行为,该代码会为setValue()调用添加完成侦听器。在我的测试中,我将设备置于飞行模式(离线),运行代码,然后禁用飞行模式以重新上线。为每个setValue()生成一条日志消息,确认写操作已排队并在重新建立连接时发送。这解释了为什么写入满足您的验证规则:客户端不发送一个具有最终值5的写入请求,它发送五个具有原始递增值的请求。

您可以通过再次运行测试来确认规则是否有效,而无需先将test的值重置为0.每次写入都将失败。

此代码还演示了Firebase客户端如何处理客户端脱机时所做的更改,以及稍后被安全规则拒绝的更改。脱机时,更改在客户端缓存中进行,onDataChange()回调使用新的(未验证的)值触发。稍后,当客户端上线并且服务器拒绝更改时,onDataChange()将再次使用之前的值触发。

final DatabaseReference ref = FirebaseDatabase.getInstance().getReference("test");

ref.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        Log.d(TAG, "onDataChange: test=" + dataSnapshot.getValue(Integer.class));
    }
    @Override
    public void onCancelled(DatabaseError databaseError) {
        throw databaseError.toException();
    }
});

final DatabaseReference.CompletionListener completionListener =
        new DatabaseReference.CompletionListener() {
    @Override
    public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
        if (databaseError == null) {
            Log.d(TAG, "setValue() Success");
        } else {
            Log.d(TAG, "setValue() Failed " + databaseError.getMessage());
        }
    }
};

ref.setValue(1, completionListener);
ref.setValue(2, completionListener);
ref.setValue(3, completionListener);
ref.setValue(4, completionListener);
ref.setValue(5, completionListener);