4

我正在开发一个简单的网络应用程序,该应用程序使用 angular 和cherrypy(目前正在制作原型)完成。我正在上传两个文件,然后在cherrypy中调用一个外部python程序来处理它们,使用子进程(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 事件并未触发。我的理解是,您可以从服务器端调用该函数,它会从浏览器中捕获事件。我错了还是设置错了?

4

2 回答 2

4

所以我发现使用 SSE,我需要以特定格式发送数据。IE

  • 数据:“foo \n\n”

或者对于 json

  • data: "{\n data: "msg" : "foo", \n data: "id" : "boo", \n data: "}\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 的好读物(如许多帖子中所述):here

于 2016-03-11T11:02:37.557 回答
2

为了补充这个自我回答的问题,我制作了这个功能齐全的示例,它包含两个文件。

文档非常有帮助。

祝大家玩得开心!

索引.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())
于 2018-12-08T11:22:48.617 回答