V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
vinsony

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

  •  1
     
  •   vinsony · Mar 24, 2021 · 9210 views
    This topic created in 1874 days ago, the information mentioned may be changed or developed.

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

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

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

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

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

    后续只要 new Date + 差值 即可
    fumichael
        13
    fumichael  
       Mar 24, 2021
    #10 response header +1
    66beta
        14
    66beta  
       Mar 24, 2021
    讲真,大部分项目 http 请求都是封装好的,拿不到 header
    存差值比较合理
    tiedan
        15
    tiedan  
       Mar 24, 2021
    所有接口加个默认字段也行
    zhs227
        16
    zhs227  
       Mar 24, 2021
    存差值,多次按远近加权平均。
    hailun3202475
        17
    hailun3202475  
       Mar 24, 2021
    我们之前的方案是 websocket 走心跳,假如每五秒一次心跳,每次心跳服务端都返回服务端时间,前端拿到时间做每次校验修正,前端时间也时刻在走
    Hoshinokozo
        18
    Hoshinokozo  
       Mar 24, 2021
    @ligolas 通信的时间要怎么拿到呢?
    jmk92
        19
    jmk92  
       Mar 24, 2021
    据我了解,一些用户机器的时间不准,即使同步了时间,可能还是过一天差一点,过不几天又不准了。
    这个要牵扯到 CPU 时钟之类的,连他的机器都无法准确计算时间,你通过 js 算法 sleep 计算时间只会更不准。
    所以只有跟服务器通信才是王道,websocket 是最优解,轮训对服务器压力大,也可以通过 10-30 秒一轮询,计算一下和本机的差值,时间等于差值+他的本地时间。
    geekvcn
        20
    geekvcn  
       Mar 24, 2021
    开个 gRPC 服务,websocket 不适合这种场景,要与时俱进
    geekvcn
        21
    geekvcn  
       Mar 24, 2021
    https://github.com/enmasseio/timesyn
    找到一个现成的库,不知道性能如何还没细看
    geekvcn
        22
    geekvcn  
       Mar 24, 2021
    还是传统的 websocket,应该轮询实现的
    ligolas
        23
    ligolas  
       Mar 24, 2021
    @Hoshinokozo 通信时间就用本地计时的差值就可以,至于精度,可以根据需求来呗,他的核心需求是客户端时间不准是因为没开 ntp 对时,所以估计是差异很大,需求可能只是要求一个跟服务器尽量统一的时间,如果精度要求不高,可以就用 Date 的差值其实也就可以了。如果需要精度高一些的,可以用 performance.now()
    xuanbg
        24
    xuanbg  
       Mar 24, 2021
    服务端渲染
    agdhole
        25
    agdhole  
       Mar 24, 2021
    很多网站都禁止时间不准的电脑访问,例如 y2b
    autoxbc
        26
    autoxbc  
       Mar 24, 2021
    @ligolas #10 自己的服务器,自己的前端,不需要 CORS 就可以读 headers
    sxlzll
        27
    sxlzll  
       Mar 24, 2021
    电脑时钟总是准的,存个基准时间比较差值呗
    indev
        28
    indev  
       Mar 25, 2021
    像 firebase 都会返回统一的服务器时间戳
    lmaq
        29
    lmaq  
       Mar 25, 2021
    ShinichiYao
        30
    ShinichiYao  
       Mar 25, 2021
    @agdhole 那以后移民火星的看不了片子了
    CEBBCAT
        31
    CEBBCAT  
       Mar 25, 2021 via Android
    @ShinichiYao 时延和时间准确不一样哦。
    @agdhole 说的应该是连接到 HTTPS 网站时加密通信失败带来的打不开
    yl20181003
        32
    yl20181003  
       Mar 25, 2021
    响应头上去取就可以了,后端配置下即可
    yazoox
        33
    yazoox  
       Mar 25, 2021
    @lmaq
    这个是直接发一个 http GET 请求就可以了?然后在返回的结果里面把 data.t 取出来?
    ```
    {"api":"mtop.common.getTimestamp","v":"*","ret":["SUCCESS::接口调用成功"],"data":{"t":"1616639029711"}}
    ```
    ligolas
        34
    ligolas  
       Mar 25, 2021
    @autoxbc 自己的前端是什么概念? cors 是浏览器端的机制,只要用户还在使用正常的,版本不是特别老的浏览器,读取 header 就必须遵守 CORS,你自己尝试一下不难
    yazoox
        35
    yazoox  
       Mar 25, 2021
    @lmaq
    试了一下,用 postman 客户端,http GET 可以成功。
    但是,用 postwoman,在线版 /PWA 版本,都是 404 。 奇怪, 我已经用 CORS 插件禁止了呢。
    ```
    Referrer Policy: strict-origin-when-cross-origin
    ```
    Yunen
        36
    Yunen  
       Mar 25, 2021
    @ShinichiYao 你放心,等你移民火星的时候,火星上的互联网公司估计早都建好机房了 XD
    xingguang
        37
    xingguang  
       Mar 25, 2021
    是不是可以换个思路,让后端来做时间之类的东西,既然要服务器的时间,那么让后端接受到接口的时候自己建立时间对象
    autoxbc
        38
    autoxbc  
       Mar 25, 2021
    @ligolas #34 CORS 是 Cross-origin resource sharing,这里根本就不 Cross-origin,不受这个限制
    ligolas
        39
    ligolas  
       Mar 25, 2021
    @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  
       Mar 25, 2021
    @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  
       Mar 25, 2021
    @autoxbc 所以我前面指出你就没理解对 CORS 的设计目的。CORS 是浏览器行为,是为了防止在浏览器端发生泄漏,服务端只是配合。那么浏览器端怎么发生泄漏呢?那就是 js,也就是如果某一个 js 执行了一段代码,读取到了**被认为**可能泄漏隐私的消息,这时候再发起一个到第三方的请求(可以是 js,也可以是 img ),就相当于把信息传递出去了,这个过程就被认为发生了泄漏。那么浏览器怎么做呢?其中一点就是限制了默认情况下 js 可以读取的 response header 的字段,也就是给你的文章里面的那 6 个,其他的,就得服务器端配合配置了才能由 js 读取到,这里面就包括了 date 字段。(另外不要弄错了,你通过开发人员工具是能读到的,cors 保证的是 js 代码读取不到)
    autoxbc
        42
    autoxbc  
       Mar 26, 2021   ❤️ 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  
       Mar 26, 2021
    按 2 楼说的 上 https 时间不对 用不了 前端就抛出个错误提示就好了。
    ligolas
        44
    ligolas  
       Mar 26, 2021
    @autoxbc 你是对的,我之前的实验有问题,执行的 js 是从 cdn 上取的,相当于没有测试过同源的情况。不过考虑到现在服务部署的方式,很多时候资源就是从 cdn 部署的,并不能保证跟主站同源,这个 CORS 还是很有可能需要的(就像我遇到的情况),非常感谢你指出了我的盲区。
    autoxbc
        45
    autoxbc  
       Mar 26, 2021
    @ligolas #44 讨论也加深了我对这块的理解。不过还是有点问题,跨域不是指**网页**和**脚本**在不同的域下,不同来源的脚本只要加载到页面里,有一致的完整的权限

    跨域指**网页**和脚本访问的另一个**网页**是不是在同一个域下,当跨域时,受 CORS 的策略的管理
    ligolas
        46
    ligolas  
       Mar 28, 2021
    @autoxbc 恩,在发完之后我继续回忆了我测试的场景,应该是主站(静态页),cdn 加载 js,然后 API,三个独立的域名,js 试图读取的是 API 的 response 的 header 。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3405 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 183ms · UTC 12:16 · PVG 20:16 · LAX 05:16 · JFK 08:16
    ♥ Do have faith in what you're doing.