【问题标题】:JavaScript function returns negative number number of seconds for the user session?JavaScript函数返回用户会话的负数秒数?
【发布时间】:2018-03-13 18:48:52
【问题描述】:

我尝试创建 JS 函数,该函数应该跟踪用户活动并在用户处于非活动状态时显示警告模式框。功能将在页面加载时启动。一些变量是全局变量,我使用它们来设置会话分钟数并将用户活动保持在屏幕上。只需计算用户会话的时间并减去出现警告之前的秒数。如果用户在页面主体上处于活动状态,我会将 JS 日期对象保存在全局变量中。一旦计时器降至 0,我将重置将注销用户并重定向到登录页面的时间或触发功能。我的代码中出现了一个问题,如果用户扩展会话(只需单击模态框中的继续按钮)计时器应该重新启动并且该部分工作正常。计时器重新启动计数和一旦达到 0 警告应该再次显示,而不是我的 expierIn 变量返回负数。我将任何等于或小于零的数字设置为 0。所以我的会话自动结束。这是错误的,我不确定为什么我的数学第二次返回负数。这是我的代码的工作示例。我没有包含应该向服务器发送 ping 以保持服务器端会话活动的 Ajax 调用。

$(document).ready(function(){
    TimeOut(); // Call session timeout function.
});

/*** Start: Session Timeout Handling(The following functions are part of session handling). ***/
var sessionMinutes = 4; // Session time in minutes.
var dmSessionBox; // Session timeout warning box
var lastActivity = null; // keeps track of user last activity
var timeout = null; // keeps timeout value
var secondsToShowDialog = 120; // number of seconds until modal shows on the screen
var dialogShowing = false; // flag to show/hide modal
var nextPoll = false; // flag to set next timeout
var lastHist = new Date(); // first time user logged to the system.
log('lastHit: '+lastHist.toLocaleTimeString());

function TimeOut() {    
    if (sessionMinutes) {
        dmSessionBox = $('<div id="sessiontimeoutwarning" class="modal fade" role="dialog"><div class="modal-dialog modal-lg"><div class="modal-content">    <div class="modal-header"><h2 class="modal-title warning"><span class="glyphicon glyphicon-warning-sign"></span>Your session is about to expire</h2></div>    <div class="modal-body"><div class="alert alert-warning warning">           <strong>Warning!</strong>Click the Continue button to extend your session.        </div></div><div class="modal-footer"><button type="button" id="continueButton" class="btn btn-primary" data-dismiss="modal">Continue</button</div>/div>/div>/div>');
        $(document.body).append(dmSessionBox);
        
        $('body').on('mousedown keydown', function(event) {
            lastActivity = new Date();
        });

        var sessionSeconds = sessionMinutes * 60; // Convert session minutes in seconds.
        log("Init - session is set to expire in " + sessionSeconds + " seconds at " + new Date(new Date().getTime() + (sessionSeconds*1000)).toLocaleTimeString());
        receiveUpdatedTimeRemaining(sessionSeconds);
    }
}

function receiveUpdatedTimeRemaining(timeout) {
    if (nextPoll)
        clearTimeout(nextPoll);

    var wakeUpMillis;

    if (timeout <= (secondsToShowDialog)) {
        if (!dialogShowing)
            lastActivity !== null ? getTimeout() : showTimeoutDialog(true);

        wakeUpMillis = 30 * 1000; 
    }else{
        showTimeoutDialog(false);
        dialogShowing = false;
        wakeUpMillis = (timeout * 1000) - (secondsToShowDialog * 1000);
    }

    log("receiveUpdatedTimeRemaining - Wake up in " + parseInt(wakeUpMillis/1000) + " for new timeout");
    nextPoll = setTimeout(getTimeout, wakeUpMillis);
}

function getTimeout() {
		clearTimeout(nextPoll);
    var currentTime = new Date().getTime(),
        lastClick = lastActivity !== null ? lastActivity.getTime() : lastHist.getTime(),
        secondsPassed = (currentTime - lastClick) / 1000, // Elapsed number of seconds since last user activity. 
        totalSeconds = sessionMinutes * 60, // Total number of seconds for this session
        expierIn = totalSeconds - secondsPassed;
        log('expierIn: '+expierIn);
		timeout = expierIn <= 0 ? 0 : expierIn; // Set time in timeout variable
    timeout == 0 ? showTimeoutErrorDialog() : receiveUpdatedTimeRemaining(timeout);
    lastActivity = null; // Reset lastActivity
}

function showTimeoutDialog(showIt) {
    dmSessionBox.find('#continueButton').on('click', function() {
        lastActivity = new Date();
        getTimeout();
    });
    showIt ? $('#sessiontimeoutwarning').modal('show') : $('#sessiontimeoutwarning').modal('hide'); 
    dialogShowing = true;
}

function showTimeoutErrorDialog() {
    $('#sessiontimeoutwarning').modal('hide'); // Close modal box
    log('Session timed out.')
}

function log(msg){  
    if (window.console && console.log) 
        console.log(new Date().toLocaleTimeString() + " :: " + msg); 
}
/*** End: Session timeout handling. ***/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<html>
<head>
  <title>Session Timeout Test</title>
</head>
<body>
  <div>My App</div>
</body>
</html>

在显示警告后,我单击继续会话将再延长 240 秒,并且警告的唤醒呼叫设置为 120 秒,但模式会话将结束而不是显示。我不确定我的变量是否没有覆盖以前的值或者我的代码中有其他错误。

【问题讨论】:

  • 请使用if 块而不是未分配的三元组,例如timeout == 0 ? showTimeoutErrorDialog() : receiveUpdatedTimeRemaining(timeout),这聪明,您的代码很难阅读/理解。
  • @James 我不确定为什么 if/else 块比三元运算符更好?准备好特定的代码行有多难?
  • @espresso_coffee 我相信评论更多的是关于使用三元进行逻辑分支而不是其预期的赋值用途,因为它返回一个值,而不是它的可读性。通常不赞成将其用于逻辑代码分支。

标签: javascript jquery session twitter-bootstrap-3 timer


【解决方案1】:

我发现所有脚本都比需要的复杂,因此决定展示一个简化的解决方案。

此版本只是在鼠标或按键活动时重新启动计时器,如果在第一次设置超时内没有,它会显示警告消息并重新启动计时器,第二次之后,它会显示注销消息并取消绑定鼠标/关键事件。

从这里您可以添加自己的模式对话框,ping 服务器等。

使用“时间戳”变量更新,因此对服务器的调用不会太频繁。

堆栈sn-p

$(document).ready(function(){
    TimeOut();
    $('body').on('mousedown keydown', function(event) {
        TimeOut();
    });
});

var TimeOut = (function(t,ts) {
  function startTimeOut() {
    // clear any warnings etc.
    document.body.innerHTML = 'My App<br>';
    if (t) {
      clearTimeout(t);
    }
    t = setTimeout(timedWarn, 5000);

    // set a time stamp and check when to ping server
    if (ts) {      
      var ct = new Date().getTime();
      //call server every e.g. 12 sec. and reset time stamp
      if ( (ct - ts) / 1000 > 12 ) {
        // sendPing();
        ts = new Date().getTime();
        console.log('send ping');
      } 
    } else {
      ts = new Date().getTime();
    }
        
  }
  function timedWarn() {
    t = setTimeout(timedOut, 5000);
    // show warn dialog
    document.body.innerHTML += 'Because of inactivity you are about to be logged out.'
  }
  function timedOut() {
    // logout, redirect
    document.body.innerHTML = 'Logged out';
    
    // unbind is not needed if a redirect is made
    $('body').unbind('mousedown keydown');
  }
  return (function() {
    startTimeOut();
  });
})();
body {
  margin: 0;
  height: 100vh;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<html>
<head>
  <title>Session Timeout Test</title>
</head>
<body>
  My App<br>
</body>
</html>

【讨论】:

  • 我查看了您的代码,非常简单。当用户应该已经注销时,您显示对话框的唯一区别。对话框应在会话到期前 60 或 120 秒显示。如果用户愿意,这将为用户提供延长会话的选项。您的示例中缺少该部分。
  • 在您的代码中我们可以使用经过时间而不是 Confirm JS 吗?因此,如果用户继续点击,我们会自动延长会话。
  • @espresso_coffee 我更新了我的答案。现在它使用 2 个计时器,一个用于警告,一个用于注销。
  • 我看到你更新了答案。还有一个问题,如果会话超时,为什么要使用 unbind?谢谢。
  • @espresso_coffee 其实只需要一个定时器,所以我又更新了。
猜你喜欢
  • 1970-01-01
  • 2013-06-27
  • 2013-02-07
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多