【问题标题】:Scripting events no longer fire when a user leaves site or closes browser even though app is still active即使应用程序仍处于活动状态,当用户离开站点或关闭浏览器时,脚本事件不再触发
【发布时间】:2013-12-24 19:25:51
【问题描述】:

我正在处理的一个项目从母版页实现了三个 JAVA 脚本“计时器”,以跟踪会话超时并进行“心跳”检查。如果在会话超时发生前超时计数达到 1 分半钟,“setTimerout”计时器会将用户重定向到警告页面。实现了两个“setInterval”计时器来跟踪用户的浏览器是否在站点上处于活动状态。以下是几个实现“定时器”和“心跳”和“心跳检查”处理程序的代码 sn-ps。

激活计时器的母版页代码:

Dim BaseAccountTimeout As Single = CType((CType(CurrentSessionTimeout, Single) - 1.5), Single)
If Session.Item("UseSessionTimeout") Then
    Dim TimeoutAcount As String = CType(((BaseAccountTimeout * 60) * 1000), Integer).ToString
    Page.ClientScript.RegisterStartupScript(Me.GetType, "TimeoutScript", "setTimeout(""top.location.href = '" & GotoTimeoutPage & "'""," & TimeoutAcount & ");", True)
End If
If Session.Item("UseHeartBeat") Then
    Dim BaseHeartBeatTimeout As Single = CType(CurrentHeartBeatTimeout, Single)
    Dim BaseHeartBeatCheckTimeout As Single = CType((BaseHeartBeatTimeout + 1.5), Single)
    Dim TimeoutHeartBeat As String = CType(((BaseHeartBeatTimeout * 60) * 1000), Integer).ToString
    Dim TimeoutHeartBeatCheck As String = CType(((BaseHeartBeatCheckTimeout * 60) * 1000), Integer).ToString
    Page.ClientScript.RegisterStartupScript(Me.GetType, "HeartBeatScript", "setInterval(""ajax.post('/pages/heartbeat.ashx', {id: '" + Session.SessionID + "'}, function() {})""," & TimeoutHeartBeat & ");", True)
    Page.ClientScript.RegisterStartupScript(Me.GetType, "HeartBeatCheckScript", "setInterval(""ajax.post('/pages/heartbeatcheck.ashx', {id: '" + Session.SessionID + "'}, function() {})""," & TimeoutHeartBeatCheck & ");", True)
End If

心跳处理程序代码:

<%@ webhandler language="VB" class="HeartbeatHandler" %>
Imports System
Imports System.Web
Imports System.Data
Imports System.Data.SqlClient
Public Class HeartbeatHandler
Implements IHttpHandler
Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable
    Get
        Return True
    End Get
End Property
Public Sub ProcessRequest(ByVal ctx As HttpContext) Implements IHttpHandler.ProcessRequest
    Dim sqlConnection1 As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString)
    Dim cmd As New System.Data.SqlClient.SqlCommand
    Dim dreader As System.Data.SqlClient.SqlDataReader
    Dim GotOne As Boolean = False
    Dim ValuesString As String = ""
    Dim FieldsString As String = ""
    Dim id As String = ""
    id = ctx.Request.Params.Item("id")
    If IsNothing(id) Then id = ""
    If id = "" Then GoTo EXITHEARTBEAT
    cmd.Connection = sqlConnection1
    cmd.CommandType = System.Data.CommandType.Text
    If cmd.Parameters.Count = 0 Then
        cmd.Parameters.Add("@uID", System.Data.SqlDbType.NVarChar)
        cmd.Parameters.Add("@Date", System.Data.SqlDbType.DateTime)
        cmd.Parameters.Add("@IP", System.Data.SqlDbType.NVarChar)
    End If
    cmd.Parameters("@uID").Value = id
    cmd.Parameters("@Date").Value = CType(Now, DateTime)
    cmd.Parameters("@IP").Value = HttpContext.Current.Request.UserHostAddress
    Try
        cmd.CommandText = "SELECT SessionID FROM aspnet_Sessions WHERE SessionID = @uID"
        sqlConnection1.Open()
        dreader = cmd.ExecuteReader()
        If dreader.Read() Then GotOne = True
        dreader.Close()
    Catch ex As Exception
        ' do nothing here
    Finally
        sqlConnection1.Close()
    End Try
    If GotOne Then
        Try
            ValuesString = "LastRequest = @Date"
            cmd.CommandText = "UPDATE aspnet_Sessions SET " + ValuesString + " WHERE SessionID = @uID"
            sqlConnection1.Open()
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            ' do nothing here
        Finally
            sqlConnection1.Close()
        End Try
    Else
        Try
            FieldsString = "(Record, LiveDate, SessionID, LastRequest, IPAddress)"
            ValuesString = "(NEWID(), @Date, @uID, @Date, @IP)"
            cmd.CommandText = "INSERT aspnet_Sessions " + FieldsString + " VALUES " + ValuesString
            sqlConnection1.Open()
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            ' do nothing here
        Finally
            sqlConnection1.Close()
        End Try
    End If
EXITHEARTBEAT:
End Sub
End Class

心跳检查处理程序代码:

<%@ webhandler language="VB" class="HeartbeatCheckHandler" %>
Imports System
Imports System.Web
Imports System.Data
Imports System.Data.SqlClient
Public Class HeartbeatCheckHandler
Implements IHttpHandler
Public ReadOnly Property IsReusable As Boolean Implements IHttpHandler.IsReusable
    Get
        Return True
    End Get
End Property
Public Sub ProcessRequest(ByVal ctx As HttpContext) Implements IHttpHandler.ProcessRequest
    Dim sqlConnection1 As New System.Data.SqlClient.SqlConnection(ConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString)
    Dim cmd As New System.Data.SqlClient.SqlCommand
    Dim dreader As System.Data.SqlClient.SqlDataReader
    Dim GotOne As Boolean = Nothing
    Dim ValuesString As String = ""
    Dim FieldsString As String = ""
    Dim LastRequest As DateTime = Nothing
    Dim TimeDifference As Long = 0
    Dim HeartBeatTimeout As Single = CommonCode.Common.DefaultHeartBeatTimeout
    Dim MissedHeartBeats As Single = CommonCode.Common.DefaultMissedHeartBeats
    Dim id As String = ""
    id = ctx.Request.Params.Item("id")
    If IsNothing(id) Then id = ""
    If id = "" Then GoTo EXITHEARTBEATCHECK
    cmd.Connection = sqlConnection1
    cmd.CommandType = System.Data.CommandType.Text
    Try
        cmd.CommandText = "SELECT HeartBeatTimeout, MaximumMissedHeartBeats FROM aspnet_WebSiteSettings"
        cmd.CommandType = System.Data.CommandType.Text
        sqlConnection1.Open()
        dreader = cmd.ExecuteReader()
        If dreader.Read() Then
            HeartBeatTimeout = dreader("HeartBeatTimeout")
            MissedHeartBeats = dreader("MaximumMissedHeartBeats")
        End If
        dreader.Close()
    Catch ex As Exception
        ' do nothing here
    Finally
        sqlConnection1.Close()
    End Try
    Dim MaximumDifference As Single = (HeartBeatTimeout * MissedHeartBeats) + 0.5
    If cmd.Parameters.Count = 0 Then cmd.Parameters.Add("@uID", System.Data.SqlDbType.NVarChar)
    cmd.Parameters("@uID").Value = id
    Try
        cmd.CommandText = "SELECT SessionID, LastRequest FROM aspnet_Sessions WHERE SessionID = @uID"
        cmd.CommandType = System.Data.CommandType.Text
        sqlConnection1.Open()
        dreader = cmd.ExecuteReader()
        If dreader.Read() Then
            If Not IsDBNull(dreader("LastRequest")) Then
                If dreader("LastRequest").ToString.Trim <> "" Then
                    LastRequest = dreader("LastRequest")
                    TimeDifference = DateDiff(DateInterval.Minute, LastRequest, CType(Now, DateTime))
                    If TimeDifference > MaximumDifference Then GotOne = True
                Else
                    GotOne = False
                End If
            Else
                GotOne = False
            End If
        Else
            GotOne = False
        End If
        dreader.Close()
    Catch ex As Exception
        ' do nothing here
    Finally
        sqlConnection1.Close()
    End Try
    If GotOne Then
        Try
            cmd.CommandText = "DELETE aspnet_Sessions WHERE SessionID = @uID"
            cmd.CommandType = System.Data.CommandType.Text
            sqlConnection1.Open()
            cmd.ExecuteNonQuery()
        Catch ex As Exception
            ' do nothing here
        Finally
            sqlConnection1.Close()
        End Try
        CommonCode.Common.DeleteFromSessionIDCollection(id)
        CommonCode.Common.SessionData(CommonCode.Common.DeleteSessionData, id)
        CommonCode.Common.DisposeSession()
    End If
EXITHEARTBEATCHECK:
End Sub
End Class

以下是母版页上的代码:

        var ajax = {};
    ajax.x = function () {
        try {
            return new ActiveXObject('Msxml2.XMLHTTP')
        } catch (e1) {
            try {
                return new ActiveXObject('Microsoft.XMLHTTP')
            } catch (e2) {
                return new XMLHttpRequest()
            }
        }
    };
    ajax.send = function (url, callback, method, data, sync) {
        var x = ajax.x();
        x.open(method, url, sync);
        x.onreadystatechange = function () {
            if (x.readyState == 4) {
                callback(x.responseText)
            }
        };
        if (method == 'POST') {
            x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        }
        x.send(data)
    };
    ajax.get = function (url, data, callback, sync) {
        var query = [];
        for (var key in data) {
            query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
        }
        ajax.send(url + '?' + query.join('&'), callback, 'GET', null, sync)
    };
    ajax.post = function (url, data, callback, sync) {
        var query = [];
        for (var key in data) {
            query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
        }
        ajax.send(url, callback, 'POST', query.join('&'), sync)
    };

我发现 JAVA 脚本计时器仅在浏览器在站点上时才会继续触发。一旦用户关闭浏览器或导航离开站点,即使 Web 应用程序仍在运行,文件的唯一事件是会话超时时 Global.asax 中的 ASP.NET“Session_End”事件。我假设没有一个“计时器”会触发,这是由于母版页不再加载,因此主页面上的脚本不会触发。

我并不真正关心“setTimeout”计时器,因为如果浏览器在站点上不再处于活动状态,则无需重定向到超时页面,这样脚本就可以留在母版页上。但是,两个“setInterval”计时器是我试图继续运行的,因此应用程序可以检测用户是否离开了站点,然后应用程序可以删除该会话的会话数据和临时目录。

我的问题是:有谁知道从服务运行这两个脚本的方法或其他实现它们的方法,这样即使浏览器关闭或转到另一个站点,它们也会继续触发?

谢谢! 大卫

附言。一点背景知识:当应用程序从存储在 SQL 数据库中的值启动时,会设置四个全局变量“CurrentSessionTimeout”、“CurrentHeartBeatTimeout”、“DefaultHeartBeatTimeout”和“DefaultMissedHeartBeats”以及两个会话变量“UseSessionTimeout”和“UseHeartBeat”。但是,两个处理程序都不使用会话变量,而是直接从全局变量或数据库中获取它们需要的任何值,因为会话可能在处理程序触发之前结束,也就是说,如果仍然加载页面,则返回原始这篇文章的原因。 :)

【问题讨论】:

  • 我在这里看不到任何 Java 代码。请注意,Java 和 Javascript 不是一回事。
  • 他正在尝试动态评估 JavaScript。问题是应用程序需要浏览器的解释器才能做到这一点。因此,如果浏览器不在页面上,它就不会发生。
  • 通过脚本管理器调用java代码...
  • @rescuecreative,没错!这就是为什么我正在寻找一种独立于浏览器页面运行 JavaScript 的方法。
  • 正确,它是使用我添加到上面原始帖子末尾的页面上的代码的脚本

标签: java javascript asp.net timer handler


【解决方案1】:

我得出的结论是,当网站上没有浏览器时,无法触发事件。似乎心跳的想法可能很“酷”,但没有实用的方法可以使其在 ASP.NET 应用程序网站上工作,该网站使用页面生成的 Javascript 代码。希望这篇文章对可能正在考虑这个问题的其他人有所帮助,并避免他们浪费时间;)

目前正在重新设计应用程序的例程以改用 Session_End 事件。当 Session_End 事件触发时,会话数据实际上已经消失,因此您不能将会话变量用于任何清理例程。相反,计划是创建一些将在 Session_Start 事件中设置的全局 App_Code 变量,然后在 Session_End 事件中使用它们来删除任何不活动的会话数据和临时目录。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多