Bình thường hóa thời gian ở phía máy khách (javascript)


8

Câu hỏi:

Làm thế nào để bạn bình thường hóa dấu thời gian phía máy khách trong javascript cho người dùng bị tắt đồng hồ máy tính bên trong? Lưu ý rằng tôi đang xử lý thời gian trong UTC.

Bối cảnh:

Tôi có một phiên bản AWS ElasticSearch được thiết lập với một số thao tác được xử lý theo đợt và được điều chỉnh trên đường đi, làm cho dấu thời gian phía máy chủ không đáng tin cậy (vì dữ liệu có thể không theo thứ tự và vấn đề thứ tự). Do đó, tôi cần phải làm cho dấu thời gian phía khách hàng của mình đáng tin cậy hơn.

Các ràng buộc:

Tôi không thể thực hiện bất kỳ yêu cầu nào phía máy chủ (cần giữ yêu cầu HTTP ở mức tối thiểu), nhưng tôi có thể bao gồm dấu thời gian phía máy chủ được tạo khi javascript của tôi được tải lần đầu tiên trên máy khách.


Giải pháp cố gắng:

Các biến được xác định bên ngoài:

  • serverTimestamp - dấu thời gian UTC (tính bằng mili giây), phía máy chủ được tạo khi javascript được tải.
  • getCookie - một hàm nhận giá trị cookie cho một khóa đã cho (hoặc một chuỗi trống nếu không tìm thấy).

Cài đặt kiểm soát bộ nhớ cache cho tệp là "public,max-age=300,must-revalidate"(5 phút).

const getTimestamp = (function() {
    // This cookie is set on the `unload` event, and so should be greater than
    // the server-side timestamp when set.
    /** @type {!number} */
    const cookieTimestamp = parseInt(getCookie("timestamp_cookie"), 10) || 0;
    // This timestamp _should_ be a maximum of 5 minutes behind on page load
    // (cache lasts 5 min for this file).
    /** @type {!number} */
    const storedTimestamp = cookieTimestamp > serverTimestamp ?
                            cookieTimestamp : serverTimestamp;
    return function () {
        /** @type {!number} */
        const timestamp = Date.now();
        // This timestamp should be, at a *maximum*, 5-6 minutes behind
        // (assuming the user doesn't have caching issues)
        /** @type {!number} */
        const backupTimestamp = storedTimestamp
            + parseFloat(window.performance.now().toFixed(0));
        // Now let's check to see if the user's clock is
        // either too fast, or too slow:
        if (
            // Timestamp is smaller than the stored one.
            // This means the user's clock is too slow.
            timestamp < backupTimestamp
            // Timestamp is more than 6 minutes ahead. User's clock is too fast.
            // (Using 6 minutes instead of 5 to have 1 minute of padding)
            || (timestamp - backupTimestamp) > 360000
        ) {
            return backupTimestamp;
        } else {
            // Seems like the user's clock isn't too fast or too slow
            // (or just maximum 1 minute fast)
            return timestamp;
        }
    }
})();

Vấn đề với giải pháp:

Sử dụng getTimestampchức năng trên , việc chạy (new Date(getTimestamp())).getUTCDate()sẽ trở lại vào ngày hôm sau đối với một số người dùng và getUTCHoursdường như ở khắp mọi nơi trong các trường hợp cạnh. Tôi không thể tự chẩn đoán vấn đề.


1
Không dấu thời gian đánh dấu ngày từ GMT, sau đó bạn có thể dịch sang TZ địa phương nếu muốn?
symlink

Tôi thực sự đang cố gắng giữ mọi thứ trong GMT / UTC. Tôi không muốn điều này cụ thể với bất kỳ múi giờ nào - Tôi đang cố gắng bình thường hóa thời gian trên các múi giờ / trình duyệt kỳ lạ.
jperezov

Sử dụng Date.toUTCString () thay vì Date.toString (): stackoverflow.com/questions/17545708/iêu
symlink

1
Bạn không thể dựa vào thời gian của Khách hàng, vì nó có thể bị thay đổi. Bạn sẽ phải dựa vào Máy chủ, nơi bạn kiểm soát thời gian. Trong PHP bạn sẽ làm một cái gì đó như<?php date_default_timezone_set('UTC'); $o = new StdClass; if(isset($_POST['get_time'])){ /* make sure AJAX get_time is set */ $o->time = time(); echo json_encode($o); /* now you have object with time property for javascript AJAX argument */ } ?>
StackSlave

1
Độ chính xác nào bạn cần (ms, s, phút?); và bạn có đủ tin tưởng khách hàng? tức là điều tồi tệ nhất có thể xảy ra với hệ thống của bạn nếu khách hàng thao túng javascript hoặc đăng dữ liệu sai? NTP tồn tại bởi vì thật khó để thực hiện đồng bộ hóa thời gian phân tán với độ chính xác, nhưng nếu bạn không quan tâm quá nhiều đến vài giây và quan tâm nhiều hơn đến việc sửa đồng hồ của khách hàng bị tắt trong một ngày hoặc lâu hơn, thì giải pháp @symcbean có lẽ là đủ. Tôi do dự vì bạn nói "vấn đề trật tự"! Tôi quan tâm đến giải pháp cuối cùng của bạn, rất thích thấy bạn đăng nó như một câu trả lời.
thinkOfaNumber

Câu trả lời:


1

Bám sát dấu thời gian ở phía khách hàng - đừng bận tâm với ngày / lần. Lưu trữ delta giữa máy chủ và đồng hồ máy khách trên máy khách. Gửi dấu thời gian của khách hàng và delta với các thông báo sau đó xây dựng lại ngày / giờ trên máy chủ.

Sau đó, bạn có thể đưa ra quyết định hợp lý bên máy chủ về cách xử lý jitter và nhảy trong đồng bộ hóa đồng hồ.


Ôi, đó là một ý tưởng thú vị để cứu đồng bằng giữa các đồng hồ. Có lẽ tôi có thể bắt đầu lưu thông tin đó để xem mức độ lớn của đồng bằng có thể nhận được và mức độ thường xuyên xảy ra sự cố này.
jperezov

0

Bạn không nên dựa vào Khách hàng trong thời gian đảm bảo. JavaScript của bạn có thể trông giống như:

var fd = new FormData, xhr = new XMLHttpRequest;
fd.append('get_time', '1'); xhr.open('POST', 'gettime.php');
xhr.onload = function(response){
  var obj = JSON.parse(response.responseText);
  console.log(obj.time);
}
xhr.send(fd);

Nếu sử dụng PHP:

<?php // gettime.php
date_default_timezone_set('UTC'); $o = new StdClass;
if(isset($_POST['get_time'])){
  $o->time = time();
  echo json_encode($o);
}
?>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.