V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
vinsony
V2EX  ›  JavaScript

前端要以服务器的时间为准,有啥好用的库吗?

  •  1
     
  •   vinsony · 128 天前 · 5083 次点击
    这是一个创建于 128 天前的主题,其中的信息可能已经有所发展或是发生改变。

    场景是大量客户端电脑时间都不准,也没有时间同步,只能在程序里请求后端时间接口获取真实时间。

    现在想法是程序只取一次服务器时间,然后在客户端模拟一个时间出来,关键要能支持 new Date 获取这个模拟时间,而且这个模拟时间能一直自动继续走。

    这样的需求有啥好用的库吗?

    46 条回复    2021-03-28 11:40:09 +08:00
    lasuar
        1
    lasuar   128 天前
    前端会 像服务器一样时刻运行着?
    zvcs
        2
    zvcs   128 天前 via iPhone   ❤️ 2
    加个 https 。如果他们时间不准就用不了
    vinsony
        3
    vinsony   128 天前
    我意思是程序运行的时候从服务器取一次时间
    zhfapiu
        4
    zhfapiu   128 天前
    计算服务端与客户端时间戳的差值,保存在前端
    MakeItGreat
        5
    MakeItGreat   128 天前 via Android   ❤️ 1
    如果客户端的时间和服务器是有差值但是差值不变
    那么根据两者固定的差值计算
    jinsongzhao
        6
    jinsongzhao   128 天前
    没有什么库,因为需要由服务端配合, 你的服务端可以是 java 的,c#的,或者时间服务等等. 而客户端如果直接修改电脑时钟,又需要权限. 其实思路也非常简单, 自己实现好了. 服务端返回时间, 客户端本地时间和服务端时间做一个差值, 然后显示时间时,始终加上这个差值. 也不用什么定时同步, 客户端不会连续工作几十天,也不会几个小时就跑出几秒的误差
    shenyuzhi
        7
    shenyuzhi   128 天前
    window.Date = function() {...}
    opp
        8
    opp   128 天前 via Android   ❤️ 1
    轮询吧,一次差值不靠谱。因为本机时间除了用户修改外,本身也会跳变,具体可搜下闹钟失效之类的案例。
    chenqh
        9
    chenqh   128 天前
    每次 api,都把服务器时间返回回去?
    这个问题我也遇到过
    ligolas
        10
    ligolas   128 天前
    response header 里面默认就带有服务器时间的,Date 字段,但是因为 CORS 的原因,你默认读不到,可以在服务器端配置一下 cors 头,你就可以读到了,这个时间再加上通信的时间,就比较准确了
    seki
        11
    seki   128 天前   ❤️ 1
    实现个 ntp 算法
    zhuweiyou
        12
    zhuweiyou   128 天前
    进来的时候 请求后端拿到服务器时间, 然后本地也 new Date, 做差值,

    是有误差 但是差值是不变的.

    后续只要 new Date + 差值 即可
    fumichael
        13
    fumichael   128 天前
    #10 response header +1
    66beta
        14
    66beta   128 天前
    讲真,大部分项目 http 请求都是封装好的,拿不到 header
    存差值比较合理
    tiedan
        15
    tiedan   128 天前
    所有接口加个默认字段也行
    zhs227
        16
    zhs227   128 天前
    存差值,多次按远近加权平均。
    hailun3202475
        17
    hailun3202475   128 天前
    我们之前的方案是 websocket 走心跳,假如每五秒一次心跳,每次心跳服务端都返回服务端时间,前端拿到时间做每次校验修正,前端时间也时刻在走
    Hoshinokozo
        18
    Hoshinokozo   128 天前
    @ligolas 通信的时间要怎么拿到呢?
    jmk92
        19
    jmk92   128 天前
    据我了解,一些用户机器的时间不准,即使同步了时间,可能还是过一天差一点,过不几天又不准了。
    这个要牵扯到 CPU 时钟之类的,连他的机器都无法准确计算时间,你通过 js 算法 sleep 计算时间只会更不准。
    所以只有跟服务器通信才是王道,websocket 是最优解,轮训对服务器压力大,也可以通过 10-30 秒一轮询,计算一下和本机的差值,时间等于差值+他的本地时间。
    geekvcn
        20
    geekvcn   128 天前
    开个 gRPC 服务,websocket 不适合这种场景,要与时俱进
    geekvcn
        21
    geekvcn   128 天前
    https://github.com/enmasseio/timesyn
    找到一个现成的库,不知道性能如何还没细看
    geekvcn
        22
    geekvcn   128 天前
    还是传统的 websocket,应该轮询实现的
    ligolas
        23
    ligolas   128 天前
    @Hoshinokozo 通信时间就用本地计时的差值就可以,至于精度,可以根据需求来呗,他的核心需求是客户端时间不准是因为没开 ntp 对时,所以估计是差异很大,需求可能只是要求一个跟服务器尽量统一的时间,如果精度要求不高,可以就用 Date 的差值其实也就可以了。如果需要精度高一些的,可以用 performance.now()
    xuanbg
        24
    xuanbg   128 天前
    服务端渲染
    agdhole
        25
    agdhole   128 天前
    很多网站都禁止时间不准的电脑访问,例如 y2b
    autoxbc
        26
    autoxbc   128 天前
    @ligolas #10 自己的服务器,自己的前端,不需要 CORS 就可以读 headers
    sxlzll
        27
    sxlzll   128 天前
    电脑时钟总是准的,存个基准时间比较差值呗
    indev
        28
    indev   128 天前
    像 firebase 都会返回统一的服务器时间戳
    lmaq
        29
    lmaq   127 天前
    ShinichiYao
        30
    ShinichiYao   127 天前
    @agdhole 那以后移民火星的看不了片子了
    CEBBCAT
        31
    CEBBCAT   127 天前 via Android
    @ShinichiYao 时延和时间准确不一样哦。
    @agdhole 说的应该是连接到 HTTPS 网站时加密通信失败带来的打不开
    yl20181003
        32
    yl20181003   127 天前
    响应头上去取就可以了,后端配置下即可
    yazoox
        33
    yazoox   127 天前
    @lmaq
    这个是直接发一个 http GET 请求就可以了?然后在返回的结果里面把 data.t 取出来?
    ```
    {"api":"mtop.common.getTimestamp","v":"*","ret":["SUCCESS::接口调用成功"],"data":{"t":"1616639029711"}}
    ```
    ligolas
        34
    ligolas   127 天前
    @autoxbc 自己的前端是什么概念? cors 是浏览器端的机制,只要用户还在使用正常的,版本不是特别老的浏览器,读取 header 就必须遵守 CORS,你自己尝试一下不难
    yazoox
        35
    yazoox   127 天前
    @lmaq
    试了一下,用 postman 客户端,http GET 可以成功。
    但是,用 postwoman,在线版 /PWA 版本,都是 404 。 奇怪, 我已经用 CORS 插件禁止了呢。
    ```
    Referrer Policy: strict-origin-when-cross-origin
    ```
    Yunen
        36
    Yunen   127 天前
    @ShinichiYao 你放心,等你移民火星的时候,火星上的互联网公司估计早都建好机房了 XD
    xingguang
        37
    xingguang   127 天前
    是不是可以换个思路,让后端来做时间之类的东西,既然要服务器的时间,那么让后端接受到接口的时候自己建立时间对象
    autoxbc
        38
    autoxbc   127 天前
    @ligolas #34 CORS 是 Cross-origin resource sharing,这里根本就不 Cross-origin,不受这个限制
    ligolas
        39
    ligolas   127 天前
    @autoxbc 我确定你没搞懂 CORS 里面的 Cross-Origin 指的什么场景,到底哪里会 Cross Origin,为什么要做这个限制。
    https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_response_header,注意这篇文章的标题:CORS-safelisted_response_header,点开链接看一下,然后再好好理解下 CORS 的本质。
    autoxbc
        40
    autoxbc   127 天前
    @ligolas #39 我读了文章,试着理解一下

    1. 当 A 站 的前端跨域访问 B 站的页面时,因为同源限制,读取的内容会被浏览器抛弃掉;
    2. 此时,如果 B 站的后端确认这些内容不是用户的机密,可以配置一个 CORS 标志,使得 A 站的前端可以读取这个内容;
    3. 文章说的是,即便配置了 CORS 标志,有些消息头仍然没有全部暴露给 A 站,这个过程会经历一个过滤器;
    4. 这个过滤器默认放行文章所述的 6 种消息头;以及,这个放行策略可以由 B 站进行扩充

    那么,回到问题,题主现在是 A 站的前端,需要从 A 站的响应里读取消息头,整个过程不需要跨域,所以不需要配置 CORS,自然更不需要管理 CORS-safelisted_response_header
    ligolas
        41
    ligolas   127 天前
    @autoxbc 所以我前面指出你就没理解对 CORS 的设计目的。CORS 是浏览器行为,是为了防止在浏览器端发生泄漏,服务端只是配合。那么浏览器端怎么发生泄漏呢?那就是 js,也就是如果某一个 js 执行了一段代码,读取到了**被认为**可能泄漏隐私的消息,这时候再发起一个到第三方的请求(可以是 js,也可以是 img ),就相当于把信息传递出去了,这个过程就被认为发生了泄漏。那么浏览器怎么做呢?其中一点就是限制了默认情况下 js 可以读取的 response header 的字段,也就是给你的文章里面的那 6 个,其他的,就得服务器端配合配置了才能由 js 读取到,这里面就包括了 date 字段。(另外不要弄错了,你通过开发人员工具是能读到的,cors 保证的是 js 代码读取不到)
    autoxbc
        42
    autoxbc   127 天前   ❤️ 1
    @ligolas #41 我觉得您可能认为 CORS 会同时作用于同域和跨域,并认为 CORS 是浏览器权限控制的全部内容,事实就如其名字,仅仅用来管理跨域访问

    对于同域消息头的访问,有这几个概念
    https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name
    这部分描述了哪些**请求**消息头是不能被脚本**修改**的

    https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_response_header_name
    这部分描述了哪些**响应**消息头是不能被脚本**修改**的

    https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/getAllResponseHeaders
    这是与本文最相关的部分,描述了同域状态下,哪些消息头是不能被脚本**读取**的

    事实上只有 Set-Cookie 和 Set-Cookie2 两个字段禁止读取,并不包含 Date

    这里有一篇文章有比较详细的讲解
    https://segmentfault.com/a/1190000004322487
    g0thic
        43
    g0thic   126 天前
    按 2 楼说的 上 https 时间不对 用不了 前端就抛出个错误提示就好了。
    ligolas
        44
    ligolas   126 天前
    @autoxbc 你是对的,我之前的实验有问题,执行的 js 是从 cdn 上取的,相当于没有测试过同源的情况。不过考虑到现在服务部署的方式,很多时候资源就是从 cdn 部署的,并不能保证跟主站同源,这个 CORS 还是很有可能需要的(就像我遇到的情况),非常感谢你指出了我的盲区。
    autoxbc
        45
    autoxbc   126 天前
    @ligolas #44 讨论也加深了我对这块的理解。不过还是有点问题,跨域不是指**网页**和**脚本**在不同的域下,不同来源的脚本只要加载到页面里,有一致的完整的权限

    跨域指**网页**和脚本访问的另一个**网页**是不是在同一个域下,当跨域时,受 CORS 的策略的管理
    ligolas
        46
    ligolas   124 天前
    @autoxbc 恩,在发完之后我继续回忆了我测试的场景,应该是主站(静态页),cdn 加载 js,然后 API,三个独立的域名,js 试图读取的是 API 的 response 的 header 。
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   1027 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 21ms · UTC 19:15 · PVG 03:15 · LAX 12:15 · JFK 15:15
    ♥ Do have faith in what you're doing.