自2017年10月29日的时间转移以来,我在使用firebase产品进行开发时遇到了一些非常奇怪的行为。
我正在开发一款带有Ionic(3)的混合应用程序。当我在浏览器(移动模拟设备)中开发和测试时,一切正常。一旦我切换到我的真实设备(三星Galaxy S7,没有root,modded或其他东西),所有带有时间戳的数据库写入都会失败。
在我的代码中,我创建了一个这样的时间戳:Date.now()
在我的firebase规则中,我通常会像这样验证时间戳:
"timestamp": {
".validate": "newData.isNumber() && newData.val() <= now"
}
对我来说,这个规则意味着,想要写入数据库的新数据必须是一个数字,新数据的值必须小于或等于当前服务器时间戳。如果其中一个条件不匹配,它将向客户发出警告。
我花了一整天调试我的代码并找到错误。当我删除(注释掉)时间戳相关规则上的.validate
键时,一切正常。
所以我玩了一下firebase规则中的时间戳值。例如,我在服务器时间戳中添加了一点缓冲区,如:(now + 10000)
(10secs)。
突然间它奏效了。我减少了值,直到它停止在我的真实设备上工作。我在(now + 5000)
(5秒)停了下来。
所以现在我的问题是,为什么这种行为就是这样。
在时间转移之前,一切正常。根据我的理解,客户端时间戳不可能超过服务器时间戳。 (除了真实设备上的本地时间被用户自己修改)。
寻求一些帮助,额外5秒的解决方法似乎有点脏。
干杯 Unkn0wn0x
BTW:每当我修改firebase规则并将它们部署到服务器上时,我都等了大约五分钟。答案 0 :(得分:0)
感谢您的注释。
我用时间戳又玩了一次,发现了不想要的行为。
这是代码,我已添加到我的函数中,想要为数据库写一个时间戳:
const test = Date.now();
const test2 = new Date().getTime();
console.log('server offset: ', snap.val());
console.log('Date.now(): ', test);
console.log('new Date().getTime(): ', test2);
console.log('estimated server timestamp (new Date().getTime() + offset): ', (test2 + snap.val()));
console.log('client timestamp (Date.now() - offset): ', (test - snap.val()));
以上代码的输出:
server offset: -2427
Date.now(): 1509730244926
new Date().getTime(): 1509730244926
estimated server timestamp (new Date().getTime() + offset): 1509730242499
client timestamp (Date.now() - offset): 1509730247353
这里的关键是负偏移。我从客户端时间戳中减去了服务器偏移量,以获得一个时间戳,该时间戳小于估计的服务器时间戳。
但是:-
和-
是+
。所以我不小心将它们加在一起而不是相互减去。
我已经执行了几次我的函数并且可以确定偏移是从执行到执行的不同。有一次+77 ms
另一次-2427ms
等等。
所以我添加了一个小代码片段,用于检查返回的服务器偏移量是正数还是负数,以便能够正确计算客户端时间戳。
const serverOffset: number = snap.val();
let clientTimestamp: number = null;
if (Math.sign(serverOffset) === 1){
clientTimestamp = Date.now() - serverOffset;
} else if (Math.sign(serverOffset) === -1){
clientTimestamp = Date.now() + serverOffset;
}
clientTimestamp现在按预期工作。
如果偏移量刚刚添加到Firebase文档中提到的客户端时间戳,也可以实现此行为。
也许应该在Firebase Docs中提到,偏移量也可以是负数而不仅仅是正数。如果本地设备时间比从互联网上提取的时间晚一秒运行,则可以轻松地再现此行为。
但为什么突然发生这种情况并且从未发生过?