Firebase 数据库规则时间戳问题
Firebase Database Rules Timestamp Issue
自从 2017 年 10 月 29 日的时移以来,我在使用 firebase 产品进行开发时 运行 出现了一些非常奇怪的行为。
我正在使用 Ionic (3) 开发混合应用程序。当我在浏览器(移动模拟设备)中开发和测试时,一切正常。一旦我切换到我的真实设备(Samsung Galaxy S7,没有 root,modded 或其他东西),所有带有时间戳的数据库写入都会失败。
在我的代码中,我创建了一个这样的时间戳:Date.now()
在我的 firebase 规则中,我通常像这样验证时间戳:
"timestamp": {
".validate": "newData.isNumber() && newData.val() <= now"
}
对我来说这条规则意味着,要写入数据库的新数据必须是一个数字,并且新数据的值必须小于或等于当前服务器时间戳。如果这些条件之一不匹配,它将向客户端发出警告。
我花了一整天的时间调试我的代码并找到了错误。当我删除(注释掉)时间戳相关规则上的 .validate
键时,一切正常。
所以我对 firebase 规则中的时间戳值进行了一些尝试。例如,我向服务器时间戳添加了一个小缓冲区,如:(now + 10000)
(10secs).
突然间它起作用了。我降低了该值,直到它在我的真实设备上停止工作。我停在 (now + 5000)
(5 秒)。
所以现在我的问题是,为什么会出现这种行为。
在时间转移之前,一切正常。以我的理解,客户端时间戳不可能领先于服务器时间戳。 (真机本地时间为用户自行修改除外)
寻求帮助,额外 5 秒的解决方法似乎有点脏。
干杯
未知0wn0x
顺便说一句:每次我修改 firebase 规则并将它们部署到服务器时,我都等了大约五分钟。
感谢您的注释。
我又玩了一次时间戳并弄清楚了不需要的行为。
这是我添加到我的函数中的代码,想要将时间戳写入数据库:
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 中提到,偏移量也可以是负数而不仅仅是正数。如果本地设备时间比从 Internet 获取的时间晚一秒钟,则可以轻松重现此行为。
但为什么会突然发生,而且以前从来没有发生过?
自从 2017 年 10 月 29 日的时移以来,我在使用 firebase 产品进行开发时 运行 出现了一些非常奇怪的行为。
我正在使用 Ionic (3) 开发混合应用程序。当我在浏览器(移动模拟设备)中开发和测试时,一切正常。一旦我切换到我的真实设备(Samsung Galaxy S7,没有 root,modded 或其他东西),所有带有时间戳的数据库写入都会失败。
在我的代码中,我创建了一个这样的时间戳:Date.now()
在我的 firebase 规则中,我通常像这样验证时间戳:
"timestamp": {
".validate": "newData.isNumber() && newData.val() <= now"
}
对我来说这条规则意味着,要写入数据库的新数据必须是一个数字,并且新数据的值必须小于或等于当前服务器时间戳。如果这些条件之一不匹配,它将向客户端发出警告。
我花了一整天的时间调试我的代码并找到了错误。当我删除(注释掉)时间戳相关规则上的 .validate
键时,一切正常。
所以我对 firebase 规则中的时间戳值进行了一些尝试。例如,我向服务器时间戳添加了一个小缓冲区,如:(now + 10000)
(10secs).
突然间它起作用了。我降低了该值,直到它在我的真实设备上停止工作。我停在 (now + 5000)
(5 秒)。
所以现在我的问题是,为什么会出现这种行为。
在时间转移之前,一切正常。以我的理解,客户端时间戳不可能领先于服务器时间戳。 (真机本地时间为用户自行修改除外)
寻求帮助,额外 5 秒的解决方法似乎有点脏。
干杯 未知0wn0x
顺便说一句:每次我修改 firebase 规则并将它们部署到服务器时,我都等了大约五分钟。
感谢您的注释。
我又玩了一次时间戳并弄清楚了不需要的行为。
这是我添加到我的函数中的代码,想要将时间戳写入数据库:
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 中提到,偏移量也可以是负数而不仅仅是正数。如果本地设备时间比从 Internet 获取的时间晚一秒钟,则可以轻松重现此行为。
但为什么会突然发生,而且以前从来没有发生过?