百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>html5教程> html5办事器推送的细致介绍-
分享文章到:

html5办事器推送的细致介绍-

发布时间:08/01 来源:未知 浏览: 关键词:
这篇文章主要介绍了html5办事器推送,小编觉得挺不错的,此刻分享给大家,也给大家做个参照 。一起追随小编过来看看吧 在各种BS架构的利用程序中,往往都但愿办事端能够自动地向客户端推送各种新闻,以达到相似于邮件、新闻、待服务项等通知。

往BS架构自身存在的题目就是,办事器不断采纳的是一问一答的机制。这就意味着要是客户端不自动地向办事器发送新闻,办事器就没法得知怎样给客户端推送新闻。

随着HTML、阅读器等各项技术、规范的开展,顺次生成了不一样的伎俩与办法能够实现办事端自动推送新闻,它们离别是:AJAX,Comet,ServerSent以及WebSocket。

本篇文章将对上述说起到的各种技术伎俩进行直白化的解释。

AJAX

正常的一个页面在阅读器中是这样工作的:

会员向赋予阅读器一个需要拜访的地址

阅读器依据这个地址拜访办事器,并与办事器之间新建一个TCP连贯(HTTP要求)

办事器依据这个地址和一些其它数据,组建一段HTML文本,将写入TCP连贯,然后关闭连贯

阅读器得到了来自办事器的HTML文本,解析并呈现了阅读器上给会员阅读

此时,会员点击了网站上任何一个或触发任何一个

提交时:

阅读器依据form的参数或者a的参数,作为拜访的地址

与办事器新建TCP连贯

办事器组建HTML文本,然后关闭连贯

阅读器将目前显示的页面捣毁,并按照新的HTML文本呈现一个新的页面给会员

我们不难发明的是整个历程中间,一旦创立了一个连贯,页面就没法再保护住了。整个历程看上去有点强买强卖,或许我只有一杯新的可乐,但你非要给我一整个套餐组合。

此时我们可以理解一下XmlHttpRequest组件,这个组件供给我们手动新建一个HTTP要求,发送我们想要的数据,办事器也可以只返回我们想要的效果,最大的益处是,当我们收到办事器的相应时,本来的页面没有被捣毁。这就好比,我喊一句"我的咖啡喝完了,我要续杯",然后办事员就拿了一杯咖啡过来,而不是会把我没吃完的套餐全部倒掉。

当我们应用AJAX实现办事器推送时,其本色是客户端不绝地向办事器扣问"有没有给我的新闻呀?",然后办事器答复"有"或"没有"来达到的实现结果。它的实现办法也很简略,应用jQuery框架封装好的AJAX调取也很利便:

function getMessage(fn) {
    $.ajax({
        url: "Handler.ashx", //一个能够供给新闻的页面
        dataType: "text",    //相应类型,可以是JSON,XML等其它类型
        type: "get",         //HTTP要求类型,还可以是post
        success: function (d, s) {
            fn(d);           //得到了正常的相应时,应用回调函数通知外部        },
        complete: function (x, s) {
            setTimeout(function () {
                getMessage(fn);
            }, 5000);       //不管相应成功或失败,在若干秒后再扣问一次办事器        }
    });
}

通过上面的代码,可以每隔5秒扣问一次办事器可否有需要处置的新闻,通过这种方式可以达到推送的结果,但是会存在一个题目:

隔断工夫越快,推送的及时性越好,办事器的消费越大;

隔断工夫越慢,推送的及时性越低,办事器的消费越小。

并且严厉地来说,这种现实方式,并不是真正意义上的办事器自动推送新闻,但因为早期技术伎俩缺乏,所以AJAX轮循成为了一种很普遍的伎俩。

下面临办事器推送事件的标准进行概括的注明。

标准

Server-sent Events 标准是 HTML 5 标准的一个组成局部,概括的标准文档见参照 资源。该标准比拼简略,主要由两个局部组成:首先个局部是办事器端与阅读器端之间的通信协定,第二局部则是在阅读器端可供 JavaScript 运用的 EventSource 对象。通信协定是基于纯文本的简略协定。办事器端的相应的内容类型是“text/event-stream”。相应文本的内容可以看成是一个事件流,由不一样的事件所组成。每个事件由类型和数据两局部组成,同时每个事件可以有一个可选的标识符。不一样事件的内容之间通过仅包括回车符和换行符的空行(“\r\n”)来分隔。每个事件的数据可能由多行组成。代码清单 1 给出了办事器端相应的示例。

办事器端相应的示例


data: first event

data: second event
id: 100

event: myevent
data: third event
id: 101

: this is a comment
data: fourth event
data: fourth event continue

如代码清单 1 所示,每个事件之间通过空行来分隔。关于每一行来说,冒号(“:”)前面表示的是该行的类型,冒号背面则是对应的值。可能的类型包含:

  1. 类型为空白,表示该行是注释,会在处置时被忽略。

  2. 类型为 data,表示该行包括的是数据。以 data 开头的行可以涌现屡次。所有这些行都是该事件的数据。

  3. 类型为 event,表示该行用来声明事件的类型。阅读器在收到数据时,会发生对应类型的事件。

  4. 类型为 id,表示该行用来声明事件的标识符。

  5. 类型为 retry,表示该行用来声明阅读器在连贯断开之后进行再次连贯以前的期待工夫。

在上面代码中,首先个事件只包括数据“first event”,会发生默许的事件;第二个事件的标识符是 100,数据为“second event”;第三个事件会发生类型为“myevent”的事件;最后一个事件的数据为“fourth event\nfourth event continue”。当有多行数据时,现实的数据由每行数据以换行符连贯而成。

要是办事器端返回的数据中包括了事件的标识符,阅读器会记载比来一次接收到的事件的标识符。要是与办事器端的连贯中止,当阅读器端再次进行连贯时,会通过 HTTP 头“Last-Event-ID”来声明最后一次接收到的事件的标识符。办事器端可以通过阅读器端发送的事件标识符来肯定从哪个事件开端来继续连贯。

关于办事器端返回的相应,阅读器端需要在 JavaScript 中运用 EventSource 对象来进行处置。EventSource 运用的是规范的事件监听器方式,只需要在对象上增加响应的事件处置办法即可。EventSource 供给了三个规范事件,如表 1 所示。

表 1. EventSource 对象供给的规范事件

名称

注明

事件处置办法

open

当做功与办事器创立连贯时发生

onopen

message

当收到办事器发送的事件时发生

onmessage

error

当涌现差错时发生

onerror

如以前所述,办事器端可以返回自定义类型的事件。关于这些事件,可以运用 addEventListener 办法来增加响应的事件处置办法。代码清单 2 给出了 EventSource 对象的运用示例。

EventSource 对象的运用示例


var es = new EventSource('events');
es.onmessage = function(e) {
    console.log(e.data);
};

es.addEventListener('myevent', function(e) {
    console.log(e.data);
});

如上所示,在指定 URL 新建出 EventSource 对象之后,可以通过 onmessage 和 addEventListener 办法来增加事件处置办法。当办事器端有新的事件发生,响应的事件处置办法会被调取。EventSource 对象的 onmessage 属性的作用相似于 addEventListener( ‘ message ’ ),不外 onmessage 属性只支撑一个事件处置办法。在介绍完办事器推送事件的标准内容之后,下面介绍办事器端的实现。

办事器端和阅读器端实现

从上一节中对通信协定的描述可以看出,办事器端推送事件是一个比拼简略的协定。办事器端的实现也相对照较简略,只需要按照协定规定的格局,返回相应内容即可。在开源社区可以寻到各种不一样的办事器端技术相对应的实现。本人开发的难度也不大。本文运用 Java 作为办事器端的实现说话。响应的实现基于开源的 jetty-eventsource-servlet 项目,见参照 资源。下面通过一个概括的示例来注明怎样运用 jetty-eventsource-servlet 项目。示例用来模拟一个物体在某个限制空间中的随机挪移。该物体从一个随机位置开端,然后从上、下、左和右四个标的目的中随机选中一个标的目的,并在该标的目的上挪移随机的距离。办事器端一直转变该物体的位置,并把位置信息推送给阅读器,由阅读器来显示。

办事器端实现

办事器端的实现由两局部组成:一局部是用来发生数据的 org.eclipse.jetty.servlets.EventSource 接口的实现,另一局部是作为阅读器拜访端点的继承自 org.eclipse.jetty.servlets.EventSourceServlet 类的 servlet 实现。下面代码给出了 EventSource 接口的实现类。

EventSource 接口的实现类 MovementEventSource


 public class MovementEventSource implements EventSource {
 
 private int width = 800;
 private int height = 600;
 private int stepMax = 5;
 private int x = 0;
 private int y = 0;
 private Random random = new Random();
 private Logger logger = Logger.getLogger(getClass().getName());
 
 public MovementEventSource(int width, int height, int stepMax) {
  this.width = width;
  this.height = height;
  this.stepMax = stepMax;
  this.x = random.nextInt(width);
  this.y = random.nextInt(height);
 }

 @Override
 public void onOpen(Emitter emitter) throws IOException {
  query(emitter); //开端生成位置信息
 }

 @Override
 public void onResume(Emitter emitter, String lastEventId)
   throws IOException {
  updatePosition(lastEventId); //更新起始位置
  query(emitter);  //开端生成位置信息
 }
 
 //依据Last-Event-Id来更新起始位置
 private void updatePosition(String id) {
  if (id != null) {
   String[] pos = id.split(",");
   if (pos.length > 1) {
    int xPos = -1, yPos = -1;
    try {
     xPos = Integer.parseInt(pos[0], 10);
     yPos = Integer.parseInt(pos[1], 10);
    } catch (NumberFormatException e) {
     
    }
    if (isValidMove(xPos, yPos)) {
     x = xPos;
     y = yPos;
    }
   }
  }
 }
 
 private void query(Emitter emitter) throws IOException {
  emitter.comment("Start sending movement information.");
  while(true) {
   emitter.comment("");
   move(); //挪移位置
   String id = String.format("%s,%s", x, y);
   emitter.id(id); //依据位置生成事件标识符
   emitter.data(id); //发送位置信息数据
   try {
    Thread.sleep(2000);
   } catch (InterruptedException e) {
    logger.log(Level.WARNING, \
               "Movement query thread interrupted. Close the connection.", e);
    break;
   }
  }
  emitter.close(); //当轮回终止时,关闭连贯
 }

 @Override
 public void onClose() {
  
 }
 
 //猎取下一个合法的挪移位置
 private void move() {
  while (true) {
   int[] move = getMove();
   int xNext = x + move[0];
   int yNext = y + move[1];
   if (isValidMove(xNext, yNext)) {
    x = xNext;
    y = yNext;
    break;
   }
  }
 }

 //推断目前的挪移位置可否合法
 private boolean isValidMove(int x, int y) {
  return x >= 0 && x <= width && y >=0 && y <= height;
 }
 
 //随机生成下一个移动位置
 private int[] getMove() {
  int[] xDir = new int[] {-1, 0, 1, 0};
  int[] yDir = new int[] {0, -1, 0, 1};
  int dir = random.nextInt(4);
  return new int[] {xDir[dir] * random.nextInt(stepMax), \
     yDir[dir] * random.nextInt(stepMax)};
 }
}

类 MovementEventSource 需要实现 EventSource 接口的 onOpen、onResume 和 onClose 办法,其中 onOpen 办法在阅读器端的连贯打开的时候被调取,onResume 办法在阅读器端从新创立连贯时被调取,onClose 办法则在阅读器关闭连贯的时候被调取。onOpen 和 onResume 办法都有一个 EventSource.Emitter 接口类型的参数,可以用来发送数据。EventSource.Emitter 接口中包括的办法包含 data、event、comment、id 和 close 等,离别对应于通信协定中各种不一样类型的事件。而 onResume 办法还额外包括一个参数 lastEventId,表示通过 Last-Event-ID 头发送过来的比来一次事件的标识符。

MovementEventSource 类中事件生成的主要逻辑在 query 办法中。该办法中包括一个无穷轮回,每隔 2 秒钟转变一次位置,同时把更新之后的位置通过 EventSource.Emitter 接口的 data 办法发送给阅读器端。每个事件都有对应的标识符,而标识符的值就是位置自身。要是连贯断开之后,阅读器从新进行连贯,可以从上一次的位置开端继续挪移该物体。

与 MovementEventSource 类对应的 servlet 实现比拼简略,只需要继承自 EventSourceServlet 类并覆写 newEventSource 办法即可。在 newEventSource 办法的实现中,需要返回一个 MovementEventSource 类的对象,如下所示。每当阅读器端创立连贯时,该 servlet 会新建一个新的 MovementEventSource 类的对象来处置该要求。

servlet 实现类 MovementServlet


 public class MovementServlet extends EventSourceServlet { 

 @Override 
 protected EventSource newEventSource(HttpServletRequest request, 
 String clientId) { 
 return new MovementEventSource(800, 600, 20); 
 } 
 }

在办事器端实现中,需要注意的是要增加响应的 servlet 过滤器支撑。这是 jetty-eventsource-servlet 项目所依赖的 Jetty Continuations 框架的请求,不然的话会涌现差错。增加过滤器的方式是在 web.xml 文件中增加代码如下所示的配置内容。

Jetty Continuations 所需 servlet 过滤器的配置


  
    continuation 
    org.eclipse.jetty.continuation.ContinuationFilter 
  
  
    continuation 
    /sse/* 
 

阅读器端实现

阅读器端的实现也比拼简略,只需要新建出 EventSource 对象,并增加响应的事件处置办法即可。下面代码给出了响应的实现。在页面中运用一个方块表示物体。当接收到新的事件时,依据事件数据中给出的坐标信息,更新方块在页面上的位置。

阅读器端的实现代码


 var es = new EventSource('sse/movement'); 
 es.addEventListener('message', function(e) { 
     var pos = e.data.split(','), x = pos[0], y = pos[1]; 
     $('#box').css({ 
         left : x + 'px', 
         top : y + 'px' 
         }); 
     });

在介绍完根本的办事器端和阅读器端实现之后,下面介绍比拼重要的 IE 的支撑。

IE 支撑

运用阅读器原生的 EventSource 对象的一个比拼大的题目是 IE 并不供给支撑。为了在 IE 上供给一样的支撑,个别有两种方法。首先种方法是在其他阅读器上运用原生 EventSource 对象,而在 IE 上则运用简易轮询或 COMET 技术来实现;别的一种做法是运用 polyfill 技术,即便用第三方供给的 JavaScript 库来屏蔽阅读器的不一样。本文运用的是 polyfill 技术,只需要在页面中加载第三方 JavaScript 库即可。利用自身的阅读器端代码并不需要进行改动。个别举荐运用第二种做法,由于这样的话,在办事器端只需要运用一种实现技术即可。

在 IE 上供给相似原生 EventSource 对象的实现并不简略。理论上来说,只需要通过 XMLHttpRequest 对象来猎取办事器端的相应内容,并通过文本解析,就可以提掏出响应的事件,并触发对应的事件处置办法。不外题目在于 IE 上的 XMLHttpRequest 对象并不支撑猎取局部的相应内容。只要在相应完成之后,才干猎取其内容。因为办事器端推送事件运用的是一个长连贯。当连贯不断处于打开状态时,通过 XMLHttpRequest 对象并不克不及猎取相应的内容,也就没法触发对应的事件。更概括的来说,当 XMLHttpRequest 对象的 readyState 为 3(READYSTATE_INTERACTIVE)时,其 responseText 属性是没法猎取的。

为理解决 IE 上 XMLHttpRequest 对象的题目,就需要运用 IE 8 中引入的 XDomainRequest 对象。XDomainRequest 对象的作用是发出跨域的 AJAX 要求。XDomainRequest 对象供给了 onprogress 事件。当 onprogress 事件产生时,可以通过 responseText 属性来猎取到相应的局部内容。这是 XDomainRequest 对象和 XMLHttpRequest 对象的最大不一样,也是运用 XDomainRequest 对象来实现相似原生 EventSource 对象的根基。在运用 XDomainRequest 对象打开与办事器端的连贯之后,当办事器端有新的数据发生时,可以通过 XDomainRequest 对象的 onprogress 事件的处置办法来进行处置,对接收到的数据进行解析,依据数据的内容触发响应的事件。

不外因为 XDomainRequest 对象原来的目的是发出跨域 AJAX 要求,考虑到跨域拜访的平安性题目,XDomainRequest 对象在运用时的限定也比拼严厉。这些限定会影响到其作为 EventSource 对象的实现方式。概括的限定和解决方法如下所示:

  1. 办事器端的相应需要包括 Access-Control-Allow-Origin 头,用来声明允许从哪些域拜访该 URL。“*”表示允许来自任何域的拜访,不举荐运用该值。个别运用与目前利用雷同的域,限定只允许来自目前域的拜访。

  2. XDomainRequest 对象发出的要求不克不及包括自定义的 HTTP 头,这就限定了不克不及运用 Last-Event-ID 头来声明阅读器端比来一次接收到的事件的标识符。只能通过 HTTP 要求的其他方式来通报该标识符,如 GET 要求的参数或 POST 要求的内容体。

  3. XDomainRequest 对象的要求的内容类型(Content-Type)只能是“text/plain”。这就意味着,当运用 POST 要求时,办事器端运用的框架,如 servlet,不会对 POST 要求的内容进行主动解析,没法运用 HttpServletRequest 类的 getParameter 办法来猎取 POST 要求的内容。只能在办事器端对原始的要求内容进行解析,猎取到其中的参数的值。

  4. XDomainRequest 对象发出的要求中不包括任何与会员认证相干的信息,包含 cookie 等。这就意味着,要是办事器端需要认证,则需要通过 HTTP 要求的其他方式来通报会员的认证信息,比方 session 的 ID 等。

因为 XDomainRequest 对象的这些限定,办事器端的实现也需要作出响应的改动。这些改动包含返回 Access-Control-Allow-Origin 头;关于阅读器端发送的“text/plain”类型的参数进行解析;处置要求中包括的会员认证相干的信息。

本文的示例运用的 polyfill 库是 GitHub 上的 Yaffle 开发的 EventSource 项目,概括的地址见参照 资源。在运用该 polyfill 库,并对办事器端的实现进行修改之后,就可以在 IE 8 及以上的阅读器中运用办事器推送事件。要是需要支撑 IE 7,则只能运用简易轮询或 COMET 技术。本文的示例代码见参照 资源。

小结

要是需要从办事器端推送数据给阅读器,可以运用的基于 HTML 5 标准规范的技术包含 WebSocket 和办事器推送事件。开发人员可以依据利用的概括需求来选中合适的技术。要是只是需要从办事器端推送数据,办事器推送事件的标准更加简略,实现起来更容易。本文对办事器推送事件的标准内容、办事器端和阅读器端的实现都进行了细致的介绍,对怎样支撑 IE 阅读器也进行了概括的剖析。

以上就是html5办事器推送的细致介绍的细致内容,更多请关注 百分百源码网 其它相干文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有151人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板