zoukankan      html  css  js  c++  java
  • Html5实践之EventSource

    最近尝试了一下服务器端的推送,之前的做法都是客户端轮询,定时向服务器发送请求。但这造成了我的一些困扰:

    1:轮询是由客户端发起的,那么在服务端就不能判别我要推送的内容是否已经过期,因为我很难判断某个信息是否已经推送给全部的客户端,那么服务端就需要缓存大量的数据。如果数据保存在数据库,那么还要每次请求都需要查询数据库,这对数据库和系统设计都是一个很大的挑战。

    2:请求的频率太高,每次的请求包中含有同样的数据,这对pc来说也许算不得什么,但是对于移动客户端来讲,这应该不是最佳的方案。尤其是遇到还要做权限判断的时候,那么服务端的逻辑和效率也会造成用户体验的降低。

    好在Html5为我们提供了一种方式: Server-Sent Events包含新的HTML元素EventSource和新的MIME类型 text/event-stream 来完成我的需要。

    因为是第一次接触Html5, w3school中也有对EventSource的说明和使用 。于是马上开始着手实践。

    页面脚本就不用说了,按照w3school的方式即可。

    var source=new EventSource("demo_sse.php");
    source.onmessage=function(event)
      {
      document.getElementById("result").innerHTML+=event.data + "<br />";
      };

    服务端的代码也是如初一折,w3school提供了php和asp的代码:

    //php方式
    <?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    $time = date('r');
    echo "data: The server time is: {$time}
    
    ";
    flush();
    ?>
    
    //asp方式
    <%
    Response.ContentType="text/event-stream"
    Response.Expires=-1
    Response.Write("data: " & now())
    Response.Flush()
    %>
    • 把报头 "Content-Type" 设置为 "text/event-stream"
    • 规定不对页面进行缓存
    • 输出发送日期(始终以 "data: " 开头)
    • 向网页刷新输出数据

    也许大家应该注意到,php和asp的案例有一点不一样,就是php推送的信息一个使用了" "作为结束标志,而asp却没有。而本人实践则是用asp.net+mvc,经过测试,如果不以" "作为结束标志,那么客户端将不能接收到推送的值。还有需要特别声明一下:推送的信息格式必须为”data:内容 “,否则。。。

    public void Subscribe()
            {
                HttpContext.Response.ContentType = "text/event-stream";
                HttpContext.Response.CacheControl = "no-cache";
                HttpContext.Response.Write("data:" + DateTime.Now.ToString()+ "
    
    ");
                HttpContext.Response.Flush();
            }

    至此,客户端应该可以收到服务端推送的值。而如此简单的结构真的可以完成我们需要的功能设计吗? 
    此例我们只是推送了一个当前时间,而我们实际要推送的值是不断变化的,不然也就没有推送的必要了。

    于是我想到了将订阅的请求保存起来,当需要推送的时候,在对每个请求进行循环推送,于是有了下面的代码:

    public class PublishService
        {
            private static IDictionary<string, HttpResponseBase> contexts = new Dictionary<string, HttpResponseBase>();
            public static void AddHttpContext(HttpContextBase context)
            {
                var token = context.GetToken(”CookieName“);
                if (!contexts.Keys.Contains(token))
                    contexts.Add(token, context.Response);
            }
    
            private static void Publish()
            {
                foreach (var context in contexts.Values)
                {
                    context.ContentType = "text/event-stream";
                    context.CacheControl = "no-cache";
                    msg = GetData(context.GetToken("CookieName"));
                    context.Write("data:" + msg + "
    
    ");
                    context.Flush();
                }
            }
            public void Subscribe()
            {
                PublishService.AddHttpContext(HttpContext);
                PublishService.Publish();
            }
        }

    可是在进行测试的时候Chrome告诉我: EventSource's response has a MIME type ("text/plain") that is not "text/event-stream". Aborting the connection.

    而FF告诉我: Firefox 无法建立到 http://localhost:8000/Location/Notification/Subscribe 服务器的连接。

    经过调试发现,在每次flush的时候发生异常:Server cannot flush a completed response.这究竟是为啥呢?不论是google,还是baidu,我都没能找到合适的答案,所以此案至今未结,如哪位知道请细说一二。

    于是乎,我放弃了这种方式,转而就推送一个时间看看是什么效果。结果发现Chrome每隔3秒向客户端推送一次,而FF是每5秒推送一次。有了这样一个发现,那么服务端的设计就应该是另一个样子:

    public void Subscribe()
            {
                var data = GetData();
    
                HttpContext.Response.ContentType = "text/event-stream";
                HttpContext.Response.CacheControl = "no-cache";
                HttpContext.Response.Write("data:" + data + "
    
    ");
                HttpContext.Response.Flush();
            }

    服务端只需要提供一个服务GetData(),这个服务用来获取我们需要推送的信息,而根据 Server-Sent Events规范推荐如果没有其他的数据要发送,那么定期的发送keep-alive注释。 其他的事情就不用我们操心了。

    这只是一个简单的使用,因为本人在使用EventSource的时候走了一些弯路,所以写出来,希望能对大家有些帮助。

    求教:EventSource.onopen和EventSource.onerror每次都会触发这两个事件,而且每次得到的结果都一样,为何?

  • 相关阅读:
    www.insidesql.org
    kevinekline----------------- SQLSERVER MVP
    Sys.dm_os_wait_stats Sys.dm_performance_counters
    如何使用 DBCC MEMORYSTATUS 命令来监视 SQL Server 2005 中的内存使用情况
    VITAM POST MORTEM – ANALYZING DEADLOCKED SCHEDULERS MINI DUMP FROM SQL SERVER
    Cargo, Rust’s Package Manager
    建筑识图入门(初学者 入门)
    Tracing SQL Queries in Real Time for MySQL Databases using WinDbg and Basic Assembler Knowledge
    Microsoft SQL Server R Services
    The Rambling DBA: Jonathan Kehayias
  • 原文地址:https://www.cnblogs.com/soundcode/p/4218187.html
Copyright © 2011-2022 走看看