Fork me on GitHub

与 Web 服务器通信 - SSE

  • XMLHttpRequest:能够从客户端发送请求到服务器端并且得到响应。一个小demo在这里
    但XHR不适合快速来回发送消息(如聊天室),并且无法将这一次调用和下一次调用联系起来(每次发起请求,服务器都要确定请求来自何方)。

  • 轮询:浏览器定期向服务器发送消息并接受服务器回答是否有数据更新。(考虑轮询间隔时间过长/过短的问题)

  • COMET(长轮询):在每次请求的时候,服务器端保持该连接在一段时间内处于打开状态,而不是在响应完成之后立即关闭。
    在打开状态的这一段时间里,有数据更新可以立即得到响应。
    上一个长连接关闭之后,浏览器立即打开一个新的长连接继续请求。

  • COMET(流):浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性向浏览器发送数据。

  • Server-Sent events:适合服务器端向客户端不断的数据推送,更容易实现了comet。但整个通信完全单向,无法知道浏览器是否响应。

  • WebSocket:浏览器能够保持对Web服务器打开的连接,从而与服务器长时间交换数据。适合聊天室、大型多人游戏、端到端写作工具等。

Server-sent events

浏览器端实现:

// 创建 EventSource 对象
var url = "http://localhost:8080";
var source = new EventSource(url);

// 监听并绑定, 当收到服务器端发送的事件时触发
source.onmessage = receiveMessage;

function receiveMessage(e) { console.log(e.data); }

// 发生错误触发
source.onerror = errorOccured;

// 关闭连接
source.close();

服务器端实现(nodeJs版):

var http = require("http");

http.createServer(start).listen(8888);

function start(req, res) {
  res.writeHead(200, { 
  	"Content-Type": "text/event-stream", 
  	"Cache-Control": "no-cache", 
  	"Access-Control-Allow-Origin": "http://localhost:8080" 
  });
  setInterval(function(){
    var content = "data:" + Date() + "\n\n";
    res.write(content);
  }, 1000);
}

这里:

  • 响应的内容类型为 "text/event-stream"
  • 响应内容可以看成是一个事件流,由不同的事件所组成。
  • 我这里发起了跨域请求,所以响应头需要包含 Access-Control-Allow-Origin, 用来指定允许哪些域访问现在的URL

每个事件组成:

  • 类型(event):声明事件的类型
  • 数据(data):以 data 开头的行可以出现多次,所有这些行都是该事件的数据。
    每个 data 后以 "\n" 分隔,一个事件的数据以 "\n\n" 结束。
  • 可选的标识符(id):声明事件的标识符。
    如果服务器端返回的数据中包含了事件标识符id,浏览器会记录最近一次接收到的id。
    如果与服务器端的连接中断,当浏览器端再次进行连接时,会通过 HTTP 头"Last-Event-ID"来声明最后一次接收到的id。 服务器端可以通过浏览器端发送的事件标识符id来确定从哪个事件开始来继续连接。
  • 等待时间(retry):声明浏览器在连接断开之后,进行再次连接之前的等待时间

比如说如下:

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

OK 基本实现就是这样啦~~ 点击查看代码

但是但是,SSE 是不支持的IE的!!接着看看IE上的实现吧!


IE8+的支持

这里使用了 polyfill 技术.

通过 XDomainRequest 发出跨域 AJAX 请求, 出于安全考虑会有严格限制:

  • 返回 Access-Control-Allow-Origin 头:
    指定允许访问的域 Access-Control-Allow-Origin.

  • 不能包含自定义的 HTTP 头:
    限制了不能使用 Last-Event-ID 头来声明浏览器端最近一次接收到的事件的标识符id.
    需要使用 GET 请求的参数或 POST 请求的内容体来传递标识符.

  • 对于浏览器端发送的"text/plain"类型的参数进行解析:
    XDomainRequest 对象的请求内容类型(Content-Type) 只能是"text/plain".
    意味着在是使用POST请求时, 只能在服务器端对原始的请求内容进行解析, 获得其中的参数值.

  • XDomainRequest 对象发出的请求中不包含任何与用户认证相关的信息(如cookie)
    需要通过 session 的 ID等其他方式来传递用户认证信息

posted on 2015-11-12 21:56  travelling-wxy  阅读(366)  评论(0编辑  收藏  举报