赞
踩
SSE是基于HTTP协议的,客户端向服务端发起一个请求,建立长连接( keep-alive connection);服务端向客户端发送(应答)不是一次性的包,而是一个数据流。
要实现SSE协议,客户端发起的请求头中需要携带:
Accept: text/event-stream
: 表示可接收事件流类型Cache-Control: no-cache
: 禁用任何的事件缓存Connection: keep-alive
: 表示正在使用持久连接如:
GET /sse HTTP/1.1 Accept: text/event-stream Cache-Control: no-cache Connection: keep-alive
SSE默认支持断线重连机制,在连接断开时会触发EventSource的error事件,同时自动重连。
服务端应答头中需要包含:
Content-Type: text/event-stream;charset=UTF-8
: 表示标准要求的事件的媒体类型和编码Transfer-Encoding: chunked
: 表示服务器流式传输动态生成的内容,因此内容大小事先未知如:
HTTP/1.1 200 Content-Type: text/event-stream;charset=UTF-8 Transfer-Encoding: chunked
事件采用UTF-8编码的文本消息:
\n\n
分隔;{key}: {value}
字段组成;字段间由单个换行符\n
分隔。:
开始,客户端应忽略:可用于防止中间代理因超时关闭连接;如:ping
。规范中定义了事件的四种字段:
id: 1
event: chat
retry: 3000
data: first
id: 2
event: chat
retry: 3000
data: second
data: second continue
注意:如果服务器端返回的数据中包含了事件的标识符id,浏览器会记录最近一次接收到的事件的标识符。当浏览器因断开重连时,会通过HTTP头Last-Event-ID
来声明最后一次接收到的事件的标识符;服务器端可根据此标识符确定从哪个事件开始来继续连接。
客户端SSE是在EventSource中实现的,EventSource内置了3个EventHandler属性、2个只读属性和1个方法:
CONNECTING(0),OPEN(1),CLOSED(2)
。'use strict'; if (window.EventSource) { // 创建 EventSource 对象连接服务器 const source = new EventSource('http://localhost:2000/stream'); // 连接成功后会触发 open 事件 source.addEventListener('open', () => { console.log('Connected'); }, false); // 服务器发送信息到客户端时,如果没有 event 字段,默认会触发 message 事件 source.addEventListener('message', e => { console.log(`data: ${e.data}`); }, false); // 自定义 EventHandler,在收到 event 字段为 slide 的消息时触发 source.addEventListener('slide', e => { console.log(`data: ${e.data}`); // => data: 7 }, false); // 连接异常时会触发 error 事件并自动重连 source.addEventListener('error', e => { if (e.target.readyState === EventSource.CLOSED) { console.log('Disconnected'); } else if (e.target.readyState === EventSource.CONNECTING) { console.log('Connecting...'); } }, false); } else { console.error('Your browser doesn\'t support SSE'); }
服务端使用基于Flask的实现
from flask import Flask, request from flask import Response from flask import render_template app = Flask(__name__) def get_message(): """this could be any function that blocks until data is ready""" time.sleep(1) s = time.ctime(time.time()) return json.dumps(['当前时间:' + s , 'a'], ensure_ascii=False) @app.route('/') def hello_world(): return render_template('index.html') @app.route('/stream') def stream(): user_id = request.args.get('user_id') print(user_id) def eventStream(): id = 0 for i in range(10): id +=1 # wait for source data to be available, then push it yield 'id: {}\nevent: add\ndata: {}\n\n'.format(id,get_message()) id +=1 yield 'id: {}\nevent: done\n\n'.format(id) return Response(eventStream(), mimetype="text/event-stream") if __name__ == '__main__': app.run(port=2000)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。