SSE前端代码
var source = new EventSource("{{proxy_url('/editpage/code/execute')}}" );
source.onmessage = function (event) {
var message = event.data;
console.log(message);
};
SSE后台代码
class SSEHandler (BaseHandler) :
def __init__ (self, application, request, **kwargs) :
super().__init__(application, request, **kwargs)
self._loop = None
self._last_id = None
def initialize (self) :
self.set_header("Content-Type" , "text/event-stream" )
self._auto_finish = False
@gen.coroutine
def emit (self, source) :
if not isinstance(source, DataSource):
raise ValueError("source not a instance of DataSource" )
if self._last_id == source.id:
self.log.warning("last send id:%s same,ignore" , self._last_id)
return
try :
self.write(source.text())
yield self.flush()
except StreamClosedError as e:
self._loop.stop()
self.finish()
self.log.warning(e)
except RuntimeError as e:
self._loop.stop()
self.finish()
self.log.warning(e)
def render_emitter (self, func, period=1000 , *args, **kwargs) :
self._loop = PeriodicCallback(lambda : {self.emit(func(*args, **kwargs))}, period)
self._loop.start()
class DataSource (object) :
"""Generic object for producing data to feed to clients."""
def __init__ (self, initial_data=None) :
self._id = uuid.uuid4().hex
self._event = None
self._data = initial_data
self._retry = None
self._comment = None
@property
def id (self) :
return self._id
@property
def event (self) :
return self._event
@property
def data (self) :
return self._data
@property
def retry (self) :
return self._retry
@property
def comment (self) :
return self._comment
def text (self) :
msg = ""
if self._id:
msg += "id:" + self._id + "\n"
if self._event:
msg += "event:" + self._event + "\n"
if self._comment:
msg += ":" + self._comment + "\n"
if self._data:
msg += "data:" + json.dumps(self._data) + "\n\n"
return msg