如何设置CherryPy服务器发送事件

5
我正在开发一个简单的网页应用,使用angular和cherrypy完成(目前是原型)。我正在上传两个文件,并在cherrypy中调用外部的python程序进行处理,使用subprocess(popen)。到目前为止,我已经可以做到这一点。我的目标是将来自外部程序的输出(通过popen捕获)传递给客户端。我的问题在于,我正在尝试在cherrypy上设置服务器发送事件,并且没有成功。

下面是我正在公开的cherrypy方法(从网页上的示例中选择):

@cherrypy.expose
def getUpdate(self):
    #Set the expected headers...
    cherrypy.response.headers["Content-Type"] = "text/event-stream;charset=utf-8"
    def content():
         yield "Hello,"
         yield "world"
    return content()

以下是 JavaScript 客户端代码(我已启用并正常使用 CORS):

var sseEvent = new EventSource('http://localhost:8090/getUpdate');
sseEvent.onmessage = function (event) {
    console.log(event);
};
sseEvent.onopen = function (event) {
  //console.log("I have started...");
};

我看过这个问题和这篇博客。然而,在从服务器端调用函数时,EventSource对象上的onmessage事件没有触发。我的理解是,您可以从服务器端调用该函数,并且它将捕获来自浏览器的事件。我的理解错误还是设置有误?
2个回答

4

我发现使用SSE时,需要按照特定的格式发送数据,例如:

  • 数据:"foo \n\n"

或者对于JSON:

  • 数据: "{\n 数据: "msg" : "foo", \n 数据: "id" : "boo", \n 数据: "}\n\n

我希望有一个重试格式,在n秒后持续轮询服务器。所以Cherrypy函数现在是:

@cherrypy.expose
def getUpdate(self, _=None):
    cherrypy.response.headers["Content-Type"] = "text/event-stream;charset=utf-8"
    if _:
        data = 'retry: 200\ndata: ' + str( self.prog_output) + '\n\n'
        return data
    else:
        def content():
            data = 'retry: 200\ndata: ' + str( self.prog_output) + '\n\n'
            return data
        return content()

getUpdate._cp_config = {'response.stream': True, 'tools.encode.encoding':'utf-8'}

现在发送的消息带有

'重试: n 微秒'

这将每隔n微秒发送数据。现在,EventSource onmessage事件正在触发,我可以愉快地阅读从服务器发送的程序输出。 :)

SSE的好文章(如许多帖子中所提到的):在此处


2
为了补充这个自问自答的问题,我制作了一个包含两个文件的完全功能性示例。
这份文档非常有帮助。详情请参见此处
祝大家玩得愉快! index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>title</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div>server-sent events</div>
    <h3>sse_handler.onmessage()</h3>
    <ul id="sse_message"></ul>

<script>

    // create a sse handler
    var sse_handler = new EventSource('http://localhost:8080/getUpdate');

    sse_handler.onmessage = function (event) {
        console.log("-- sse_handler.onmessage()", event);
        /* the onmessage method catch all generic message, those with no event field
        */
        var h_ul = document.getElementById('sse_message');
        var h_li = document.createElement("li");

        h_li.innerHTML = event.data;
        h_ul.appendChild(h_li);
    };

    sse_handler.onopen = function (event) {
        console.log("-- sse_handler.onopen()", event);
    };

</script>
</body>
</html>

以及server.py

#!/usr/bin/env python3

import datetime

import cherrypy

from pathlib import Path

class TestServerSentEvent(object):
    @cherrypy.expose
    def index(self):
        return Path("index.html").read_text()

    @cherrypy.expose
    def getUpdate(self, * pos, ** nam):
        cherrypy.response.headers["Content-Type"] = "text/event-stream;charset=utf-8"
        return 'retry: 1200\ndata: {0}\n\n'.format(self.output())

    def output(self) :
        d = datetime.datetime.now()
        return f"TEST - {d}"

    getUpdate._cp_config = {'response.stream': True, 'tools.encode.encoding':'utf-8'}

if __name__ == '__main__':
    cherrypy.quickstart(TestServerSentEvent())

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接