Asp classic 使用经典ASP的服务器发送事件(SSE):实现LastEventID并支持多个侦听器

Asp classic 使用经典ASP的服务器发送事件(SSE):实现LastEventID并支持多个侦听器,asp-classic,server-sent-events,eventsource,Asp Classic,Server Sent Events,Eventsource,显然,由于Internet Explorer不支持服务器发送的事件,所以为经典ASP编写的示例很少。大多数已发布的示例都使用NodeJS或PHP,但本网站和其他网站上的文章指出或暗示可以使用任何中间件语言 我已经获得了使用ASP(使用VBS)的基本代码,但确实不了解两件事:如何将最新的EventID成功发送到特定的侦听器,以及我的代码需要在多大程度上(如果有的话)跟踪当前侦听器的列表。完全公开——我对这种代码没有什么“感觉”。例如,我花了一段时间才意识到,从服务器发送的“消息”只是使用常规文本输

显然,由于Internet Explorer不支持服务器发送的事件,所以为经典ASP编写的示例很少。大多数已发布的示例都使用NodeJS或PHP,但本网站和其他网站上的文章指出或暗示可以使用任何中间件语言

我已经获得了使用ASP(使用VBS)的基本代码,但确实不了解两件事:如何将最新的EventID成功发送到特定的侦听器,以及我的代码需要在多大程度上(如果有的话)跟踪当前侦听器的列表。完全公开——我对这种代码没有什么“感觉”。例如,我花了一段时间才意识到,从服务器发送的“消息”只是使用常规文本输出的语法,即Response.Write

好的,在我问两个问题之前,这里是我正在使用的代码。这是我找到的一个PHP示例()。它从正在读取的数组中输出值(看起来像股票价格数据)。在php示例中,sleep()函数用于在事件之间设置延迟。在asp中,我使用了一种在评论(见下文)中向我建议的不同技术,它产生大约3秒的同步延迟。 下面是服务器端ASP代码:

<%@ LANGUAGE="VBSCRIPT" %>
<%
    Dim demoarr(21,1)
        demoarr(0,0) = "GOOG"
        demoarr(0,1) =  533.37 
        demoarr(1,0) = "MSFT"
        demoarr(1,1) =   47.59 
        demoarr(2,0) = "IBM"
        demoarr(2,1) =   162.99 
        demoarr(3,0) = "AAPL"
        demoarr(3,1) =  114.12 
        demoarr(4,0) = "MSFT"
        demoarr(4,1) =   47.29 
        demoarr(5,0) = "GOOG"
        demoarr(5,1) =  533.95 
        demoarr(6,0) = "IBM"
        demoarr(6,1) =   163.78 
        demoarr(7,0) = "GOOG"
        demoarr(7,1) =  533.55 
        demoarr(8,0) = "AAPL"
        demoarr(8,1) =  113.67 
        demoarr(9,0) = "GOOG"
        demoarr(9,1) =  533.91 
        demoarr(10,0) = "MSFT"
        demoarr(10,1) =   48.12 
        demoarr(11,0) = "IBM"
        demoarr(11,1) =   162.37 
        demoarr(12,0) = "AAPL"
        demoarr(12,1) =  114.12 
        demoarr(13,0) = "MSFT"
        demoarr(13,1) =   48.05 
        demoarr(14,0) = "AAPL"
        demoarr(14,1) =  114.32 
        demoarr(15,0) = "GOOG"
        demoarr(15,1) =  533.97 
        demoarr(16,0) = "MSFT"
        demoarr(16,1) =   48.54 
        demoarr(17,0) = "IBM"
        demoarr(17,1) =   162.69 
        demoarr(18,0) = "AAPL"
        demoarr(18,1) =  114.45 
        demoarr(19,0) = "IBM"
        demoarr(19,1) =   162.74 
        demoarr(20,0) = "AAPL"
        demoarr(20,1) =  114.67 

    response.ContentType = "text/event-stream"
    response.AddHeader "Cache-Control", "no-cache"
    response.AddHeader "Connection", "keep-alive"

    lastID = 0
    pickstock = 0
    Do While True
        pickstock = (pickstock + 1) MOD 20
        lastid = lastid + 2
        sendMessage lastId, demoarr(pickstock,0), demoarr(pickstock,1)
        sendMessage lastId+1, demoarr(pickstock,0), demoarr(pickstock,1)
        x = sleep(3)        
    Loop

Function sendMessage(id, ticket, price)
    Response.Write "id: " & id & vbcrlf & vbcrlf
    response.flush
    Response.Write "data: " & ticket & ":" & price & vbcrlf & vbcrlf
    response.flush
End Function    

Function sleep(scs)
    Dim lo_wsh, ls_cmd
    Set lo_wsh = CreateObject( "WScript.Shell" )
    ls_cmd = "%COMSPEC% /c ping -n " & 1 + scs & " 127.0.0.1>nul"
    lo_wsh.Run ls_cmd, 0, True 
End Function %>

下面是客户端html/javascript:

<!doctype html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <title>Server Sent Events ASP Example - Stock Tickets</title>

<style media="screen" type="text/css">

H1 {
    text-align: center;
    font-size: 150%;
    margin-bottom: 60px;
}

H2 {
    text-align: center;
    font-size: 125%;
    margin-bottom: 15px;
}

DIV#tickets {
    margin: 10px auto 80px auto;
}

DIV.ticket {
    margin: 5px auto;
    width: 160px;
    font-size: 115%;
}

DIV.name {
    display: inline-block;
    width: 80px;
    padding: 3px;
}

DIV.price {
    display: inline-block;
    width: 60px;
    padding: 3px;
    text-align: right;
    transition: all 0.2s ease-out;
}

DIV#log {
    margin: 10px auto;
    width: 600px;
    height: 200px;
    background: gainsboro;
    padding: 5px;
    overflow-y: scroll;
}

DIV#notSupported {
    display: none;
    margin: 10px auto;
    text-align: center;
    color: red;
    font-size: 150%;
}

P.hint {
    width: 600px;
    margin: 10px auto;
    text-align: justify;
    text-indent: 20px;
    line-height: 135%;
}

DIV#download {
    margin: 50px auto;
    text-align: center;
}

DIV#download A {
    padding: 10px 25px;
    background: #F1592A;
    color: white;
    text-decoration: none;
    font-size: 20px;
    border-radius: 5px 5px;
}

DIV#download A:hover {
    text-decoration: underline;
    background: #FF592A;
}

</style>

<script type="text/javascript">

    window.onload = function setDataSource() {
        if (!!window.EventSource) {
            var source = new EventSource("stocks.asp");

            source.addEventListener("message", function(e) {
                updatePrice(e.data);
                logMessage(e);
            }, false);
            
            source.addEventListener("open", function(e) {
                logMessage("OPENED");
            }, false);

            source.addEventListener("error", function(e) {
                logMessage("ERROR");
                if (e.readyState == EventSource.CLOSED) {
                    logMessage("CLOSED");
                }
            }, false);
        } else {
            document.getElementById("notSupported").style.display = "block";
        }
    }

    function updatePrice(data) {
        var ar = data.split(":");
        var ticket = ar[0];
        var price = ar[1];
        var el = document.getElementById("t_" + ticket);
        var oldPrice = el.innerHTML;
        el.innerHTML = price;
        if (parseFloat(oldPrice) < parseFloat(price)) {
            el.style.backgroundColor = "lightgreen";
        } else {
            el.style.backgroundColor = "tomato";
        }
        window.setTimeout(function clearBackground() {
            el.style.backgroundColor = "white";
        }, 500);
    }

    function logMessage(obj) {
        var el = document.getElementById("log");
        if (typeof obj === "string") {
            el.innerHTML += obj + "<br>";
        } else {
            el.innerHTML += obj.lastEventId + " - " + obj.data + "<br>";
        }
        el.scrollTop += 20;
    }

</script>

</head>

<body>

<h1>Server Sent Events ASP Example</h1>

<div id="notSupported">
    Your browser does not support Server Sent Events.
    Please use <a href="https://www.mozilla.org/firefox/new/">Firefox</a>
    or <a href="https://www.google.com/chrome/browser">Google Chrome</a>.
</div>

<h2>Tickets</h2>

<div id="tickets">
    <div class="ticket"><div class="name">IBM</div><div class="price" id="t_IBM">161.57</div></div>
    <div class="ticket"><div class="name">AAPL</div><div class="price" id="t_AAPL">114.45</div></div>
    <div class="ticket"><div class="name">GOOG</div><div class="price" id="t_GOOG">532.94</div></div>
    <div class="ticket"><div class="name">MSFT</div><div class="price" id="t_MSFT">47.12</div></div>
</div>


<h2>Simple Log Console</h2>
<p class="hint">
    This is simple log console. It is useful for testing purposes and to understand better how SSE works.
    Event id and data are logged for each event.
</p>
<div id="log">
</div>


</body>
</html>

服务器发送事件ASP示例-股票票据
H1{
文本对齐:居中;
字体大小:150%;
边缘底部:60px;
}
氢{
文本对齐:居中;
字体大小:125%;
边缘底部:15px;
}
分区票{
利润率:10px自动80px自动;
}
分区票{
保证金:5px自动;
宽度:160px;
字体大小:115%;
}
部门名称{
显示:内联块;
宽度:80px;
填充:3倍;
}
分区价格{
显示:内联块;
宽度:60px;
填充:3倍;
文本对齐:右对齐;
过渡:所有0.2秒缓解;
}
DIV#log{
利润率:10px自动;
宽度:600px;
高度:200px;
背景:gainsboro;
填充物:5px;
溢出y:滚动;
}
DIV#不受支持{
显示:无;
利润率:10px自动;
文本对齐:居中;
颜色:红色;
字体大小:150%;
}
提示{
宽度:600px;
利润率:10px自动;
文本对齐:对齐;
文本缩进:20px;
线高:135%;
}
DIV#下载{
保证金:50px自动;
文本对齐:居中;
}
下载{
填充:10px 25px;
背景#F1592A;
颜色:白色;
文字装饰:无;
字体大小:20px;
边界半径:5px 5px;
}
下载A:悬停{
文字装饰:下划线;
背景#FF592A;
}
window.onload=函数setDataSource(){
如果(!!window.EventSource){
var source=新事件源(“stocks.asp”);
source.addEventListener(“消息”,函数(e){
更新价格(如数据);
日志信息(e);
},假);
source.addEventListener(“打开”,函数(e){
日志信息(“打开”);
},假);
source.addEventListener(“错误”,函数(e){
日志信息(“错误”);
if(e.readyState==EventSource.CLOSED){
日志信息(“已关闭”);
}
},假);
}否则{
document.getElementById(“不受支持”).style.display=“块”;
}
}
函数updatePrice(数据){
var ar=data.split(“:”);
var票据=ar[0];
var价格=应收账款[1];
var el=document.getElementById(“t_”+票证);
var oldPrice=el.innerHTML;
el.innerHTML=价格;
if(parseFloat(oldPrice)”;
}否则{
el.innerHTML+=obj.lastEventId+“-”+obj.data+“
”; } el.scrollTop+=20; } 服务器发送事件ASP示例 您的浏览器不支持服务器发送的事件。 请使用 或 售票处 IBM161.57 AAPL114.45 GOOG532.94 MSFT47.12 简单日志控制台

这是一个简单的日志控制台。这对于测试目的和更好地理解SSE的工作原理非常有用。 记录每个事件的事件id和数据。

(请忽略OnEventListener而不是onmessage的使用——我可能没有说明最好的语法,但我不认为这是问题的原因)

这些来源是有效的,但非常古怪。例如,如果我不连续两次调用SendMessage,它将不起作用,而且服务器上似乎需要两个Response.flush语句。这是为什么

更重要的是,lastID应该如何处理。在PHP代码中,有一个叫做$\u SERVER\u LAST\u EVENT\u ID的东西。那是什么?是否有ASP的等价物?这有关系吗?我还没有尝试让事件ID根据SSE文档工作,这些文档显示了用于帮助断开连接的ID

关于这一点,我还有很多问题,但最重要的是,服务器上到底发生了什么?例如,如果我要建立一个到数据库的连接(MSSQL),以检查某个特定记录是否已被修改,并且有10个侦听器,这是否意味着有10个数据库连接,或者测试/事件流内容类型神奇地处理了这一问题?我在Remy Sharp的博客(html5doctor.com/server-sent-events/)中读到,“为了发布新事件,您需要维护一个所有连接用户的列表。”这是真的吗?事件流对象不是“自动”处理这个方面吗?你为什么要这么做