保持 ASP.NET 会话打开/活动

只要用户打开浏览器窗口,保持 ASP.NET 会话活动的最简单和最不引人注目的方法是什么?是定时的 AJAX 调用吗?我想防止以下情况: 有时用户长时间打开窗口,然后输入内容,在提交时,由于服务器端会话过期,不再有任何效果。我不想在服务器上增加超时值超过10分钟,因为我想关闭会话(通过关闭浏览器窗口)快速超时。

建议,代码样本?

134740 次浏览

我使用 JQuery 对一个虚拟 HTTP 处理程序执行一个简单的 AJAX 调用,该处理程序除了保持我的 Session 活动之外什么也不做:

function setHeartbeat() {
setTimeout("heartbeat()", 5*60*1000); // every 5 min
}


function heartbeat() {
$.get(
"/SessionHeartbeat.ashx",
null,
function(data) {
//$("#heartbeat").show().fadeOut(1000); // just a little "red flash" in the corner :)
setHeartbeat();
},
"json"
);
}

会话处理程序可以简单如下:

public class SessionHeartbeatHttpHandler : IHttpHandler, IRequiresSessionState
{
public bool IsReusable { get { return false; } }


public void ProcessRequest(HttpContext context)
{
context.Session["Heartbeat"] = DateTime.Now;
}
}

The key is to add IRequiresSessionState, otherwise Session won't be available (= null). The handler can of course also return a JSON serialized object if some data should be returned to the calling JavaScript.

通过 web.config 提供:

<httpHandlers>
<add verb="GET,HEAD" path="SessionHeartbeat.ashx" validate="false" type="SessionHeartbeatHttpHandler"/>
</httpHandlers>

于2012年8月14日从 Balexandre增加

I liked so much of this example, that I want to improve with the HTML/CSS and the beat part

改变这一切

//$("#heartbeat").show().fadeOut(1000); // just a little "red flash" in the corner :)

进入

beatHeart(2); // just a little "red flash" in the corner :)

然后加

// beat the heart
// 'times' (int): nr of times to beat
function beatHeart(times) {
var interval = setInterval(function () {
$(".heartbeat").fadeIn(500, function () {
$(".heartbeat").fadeOut(500);
});
}, 1000); // beat every second


// after n times, let's clear the interval (adding 100ms of safe gap)
setTimeout(function () { clearInterval(interval); }, (1000 * times) + 100);
}

HTML and CSS

<div class="heartbeat">&hearts;</div>


/* HEARBEAT */
.heartbeat {
position: absolute;
display: none;
margin: 5px;
color: red;
right: 0;
top: 0;
}

here is a 活生生的例子 for only the beating part: http://jsbin.com/ibagob/1/

您真的需要保留会话(您的会话中有数据吗?)或者当一个请求进来时,通过重新启动会话来伪造这一点就足够了吗?如果是第一个,使用上面的方法。如果是第二种情况,请尝试使用 Session _ End 事件处理程序。

If you have Forms Authentication, then you get something in the Global.asax.cs like

FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(formsCookie.Value);
if (ticket.Expired)
{
Request.Cookies.Remove(FormsAuthentication.FormsCookieName);
FormsAuthentication.SignOut();
...
}
else
{   ...
// renew ticket if old
ticket = FormsAuthentication.RenewTicketIfOld(ticket);
...
}

并且您设置的票据生命期比会话生命期长得多。如果您没有进行身份验证,或者没有使用不同的身份验证方法,也有类似的技巧。微软的 TFS 网页界面和 SharePoint 似乎都在使用这些功能——暴露出来的是,如果你在一个过时的页面上点击一个链接,你会在弹出窗口中看到身份验证提示,但是如果你只是使用一个命令,它就能工作。

If you are using ASP.NET MVC – you do not need an additional HTTP handler and some modifications of the web.config file. All you need – just to add some simple action in a Home/Common controller:

[HttpPost]
public JsonResult KeepSessionAlive() {
return new JsonResult {Data = "Success"};
}

编写一段像下面这样的 JavaScript 代码(我已经把它放在了网站的一个 JavaScript 文件中) :

var keepSessionAlive = false;
var keepSessionAliveUrl = null;


function SetupSessionUpdater(actionUrl) {
keepSessionAliveUrl = actionUrl;
var container = $("#body");
container.mousemove(function () { keepSessionAlive = true; });
container.keydown(function () { keepSessionAlive = true; });
CheckToKeepSessionAlive();
}


function CheckToKeepSessionAlive() {
setTimeout("KeepSessionAlive()", 5*60*1000);
}


function KeepSessionAlive() {
if (keepSessionAlive && keepSessionAliveUrl != null) {
$.ajax({
type: "POST",
url: keepSessionAliveUrl,
success: function () { keepSessionAlive = false; }
});
}
CheckToKeepSessionAlive();
}

, and initialize this functionality by calling a JavaScript function:

SetupSessionUpdater('/Home/KeepSessionAlive');

请注意!我只对授权用户实现了这个功能(在大多数情况下没有理由为客户保持会话状态) ,保持会话状态活动的决定不仅取决于-浏览器是否打开,而且授权用户必须在站点上做一些活动(移动鼠标或键入一些键)。

Whenever you make a request to the server the session timeout resets. So you can just make an ajax call to an empty HTTP handler on the server, but make sure the handler's cache is disabled, otherwise the browser will cache your handler and won't make a new request.

Keepsessionalive.ashx.cs

public class KeepSessionAlive : IHttpHandler, IRequiresSessionState
{


public void ProcessRequest(HttpContext context)
{
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetExpires(DateTime.UtcNow.AddMinutes(-1));
context.Response.Cache.SetNoStore();
context.Response.Cache.SetNoServerCaching();
}
}

。约翰逊:

window.onload = function () {
setInterval("KeepSessionAlive()", 60000)
}


function KeepSessionAlive() {
url = "/KeepSessionAlive.ashx?";
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", url, true);
xmlHttp.send();
}

@ veggerby-不需要在会话中存储变量的开销。只是预先向服务器发送请求就足够了。

如果客户机进入睡眠模式,这里有一个替代的解决方案应该可以生存。

如果您有大量的登录用户,那么请谨慎地使用它,因为这可能会占用大量的服务器内存。

登录后(我在登录控件的 LoggedIn 事件中执行此操作)

Dim loggedOutAfterInactivity As Integer = 999 'Minutes


'Keep the session alive as long as the authentication cookie.
Session.Timeout = loggedOutAfterInactivity


'Get the authenticationTicket, decrypt and change timeout and create a new one.
Dim formsAuthenticationTicketCookie As HttpCookie = _
Response.Cookies(FormsAuthentication.FormsCookieName)


Dim ticket As FormsAuthenticationTicket = _
FormsAuthentication.Decrypt(formsAuthenticationTicketCookie.Value)
Dim newTicket As New FormsAuthenticationTicket(
ticket.Version, ticket.Name, ticket.IssueDate,
ticket.IssueDate.AddMinutes(loggedOutAfterInactivity),
ticket.IsPersistent, ticket.UserData)
formsAuthenticationTicketCookie.Value = FormsAuthentication.Encrypt(newTicket)

你可以在你的 java 脚本文件中写这段代码。

$(document).ready(function () {
var delay = (20-1)*60*1000;
window.setInterval(function () {
var url = 'put the url of some Dummy page';
$.get(url);
}, delay);
});

(20-1)*60*1000是刷新时间,它将刷新会话超时。刷新超时计算为 iis = 20分钟的默认时间,表示20 × 60000 = 1200000毫秒-60000毫秒(会话到期前一分钟)为1140000。

我花了几天时间试图找出如何通过弹出对话框延长 WebForms 中的用户会话,该对话框允许用户选择是续订会话还是允许会话过期。你需要知道的第一件事是,你不需要在其他的一些答案中出现任何这种花哨的“ HttpContext”东西。你所需要的只是 jQuery 的 $。方法。例如,在调试时,我使用:

$.post("http://localhost:5562/Members/Location/Default.aspx");

在你的网站上,你可以使用这样的东西:

$.post("http://mysite/Members/Location/Default.aspx");

就这么简单。此外,如果您希望提示用户选择续订会话,请执行以下类似的操作:

    <script type="text/javascript">
$(function () {
var t = 9;
var prolongBool = false;
var originURL = document.location.origin;
var expireTime = <%= FormsAuthentication.Timeout.TotalMinutes %>;


// Dialog Counter
var dialogCounter = function() {
setTimeout( function() {
$('#tickVar').text(t);
t--;
if(t <= 0 && prolongBool == false) {
var originURL = document.location.origin;
window.location.replace(originURL + "/timeout.aspx");
return;
}
else if(t <= 0) {
return;
}
dialogCounter();
}, 1000);
}


var refreshDialogTimer = function() {
setTimeout(function() {
$('#timeoutDialog').dialog('open');
}, (expireTime * 1000 * 60 - (10 * 1000)) );
};


refreshDialogTimer();


$('#timeoutDialog').dialog({
title: "Session Expiring!",
autoOpen: false,
height: 170,
width: 350,
modal: true,
buttons: {
'Yes': function () {
prolongBool = true;
$.post("http://localhost:5562/Members/Location/Default.aspx");
refreshDialogTimer();
$(this).dialog("close");
},
Cancel: function () {
var originURL = document.location.origin;
window.location.replace(originURL + "/timeout.aspx");
}
},
open: function() {
prolongBool = false;
$('#tickVar').text(10);
t = 9;
dialogCounter();
}
}); // end timeoutDialog
}); //End page load
</script>

不要忘记将对话框添加到 html:

        <div id="timeoutDialog" class='modal'>
<form>
<fieldset>
<label for="timeoutDialog">Your session will expire in</label>
<label for="timeoutDialog" id="tickVar">10</label>
<label for="timeoutDialog">seconds, would you like to renew your session?</label>
</fieldset>
</form>
</div>

Here JQuery plugin version of Maryan solution with handle optimization. Only with JQuery 1.7+!

(function ($) {
$.fn.heartbeat = function (options) {
var settings = $.extend({
// These are the defaults.
events: 'mousemove keydown'
, url: '/Home/KeepSessionAlive'
, every: 5*60*1000
}, options);


var keepSessionAlive = false
, $container = $(this)
, handler = function () {
keepSessionAlive = true;
$container.off(settings.events, handler)
}, reset = function () {
keepSessionAlive = false;
$container.on(settings.events, handler);
setTimeout(sessionAlive, settings.every);
}, sessionAlive = function () {
keepSessionAlive && $.ajax({
type: "POST"
, url: settings.url
,success: reset
});
};
reset();


return this;
}
})(jQuery)

以及它如何导入到您的 * . cshtml 中

$('body').heartbeat(); // Simple
$('body').heartbeat({url:'@Url.Action("Home", "heartbeat")'}); // different url
$('body').heartbeat({every:6*60*1000}); // different timeout

In regards to veggerby's solution, if you are trying to implement it on a VB app, be careful trying to run the supplied code through a translator. The following will work:

Imports System.Web
Imports System.Web.Services
Imports System.Web.SessionState


Public Class SessionHeartbeatHttpHandler
Implements IHttpHandler
Implements IRequiresSessionState


ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property


Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Session("Heartbeat") = DateTime.Now
End Sub
End Class

另外,不要调用 like heart ()函数,比如:

 setTimeout("heartbeat()", 300000);

相反,可以这样说:

 setInterval(function () { heartbeat(); }, 300000);

第一,setTimeout 只触发一次,而 setInterval 会重复触发。第二,像调用字符串一样调用 heart ()对我来说不起作用,而像调用实际函数一样调用它就起作用了。

而且我完全可以百分之百确定这个解决方案将克服 GoDaddy 在 Plesk 强迫5分钟阿波会议的荒谬决定!

[派对迟到了... ]

另一种不需要 Ajax 调用或 WebService 处理程序开销的方法是在给定的时间后加载一个特殊的 ASPX 页面(即,在会话状态超时之前,通常为20分钟) :

// Client-side JavaScript
function pingServer() {
// Force the loading of a keep-alive ASPX page
var img = new Image(1, 1);
img.src = '/KeepAlive.aspx';
}

KeepAlive.aspx页面只是一个空白页面,它只是触摸/刷新 Session状态:

// KeepAlive.aspx.cs
public partial class KeepSessionAlive: System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Refresh the current user session
Session["refreshTime"] = DateTime.UtcNow;
}
}

这是通过创建一个 img(image)元素并强制浏览器从 KeepAlive.aspx页面加载其内容来实现的。加载该页面将导致服务器触摸(更新) Session对象,从而延长会话的到期滑动时间窗口(通常为另外20分钟)。实际的网页内容被浏览器丢弃。

另一种可供选择的、也许更简洁的方法是创建一个新的 iframe元素并将 KeepAlive.aspx页面加载到其中。iframe元素是隐藏的,例如将其作为页面上某个隐藏的 div元素的子元素。

可以通过拦截整个页面正文的鼠标和键盘操作来检测页面本身的活动:

// Called when activity is detected
function activityDetected(evt) {
...
}


// Watch for mouse or keyboard activity
function watchForActivity() {
var opts = { passive: true };
document.body.addEventListener('mousemove', activityDetected, opts);
document.body.addEventListener('keydown', activityDetected, opts);
}

我不能把这个想法归功于自己; 参见: Https://www.codeproject.com/articles/227382/alert-session-time-out-in-asp-net.