Redis 发布订阅给出错误结果

0 投票
1 回答
510 浏览
提问于 2025-04-18 18:18

Redis在处理SSE事件时给出的结果不正确。

下面这段代码在Python命令行界面中是可以正常工作的:

def stream():
    pubsub = reds.pubsub()
    pubsub.subscribe('chat')
    for message in pubsub.listen():
        return 'data: %s\n\n' % message['data']

比如,当我从Redis终端执行 PUBLISH chat "hello" 时,它返回的结果是 'data: hello\n\n'

但是在Bottle.py中,下面这段代码却不行:

@get('/stream')
def stream():
    response.content_type = 'text/event-stream'
    response.set_header('Cache-Control', 'no-cache')

    pubsub = reds.pubsub()
    pubsub.subscribe('chat')
    for message in pubsub.listen():
        return 'data: %s\n\n' % message['data']

@get('/test')
def test():
    return """
        <!DOCTYPE html>
<html>
<body>

<h1>Getting server updates</h1>
<div id="result"></div>

<script>
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource('/stream');
    source.onmessage = function(event) {
        document.getElementById("result").innerHTML += event.data + "<br>";
    };
} else {
    document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>

</body>
</html>
"""

当我访问 127.0.0.1:8000/test 时,每隔几秒我看到的内容是:

1
1
1
1
1
1
1
1
...

而我应该看到的是:

hello
hi
howdy
...

如果我把它改成:

@get('/stream')
    def stream():
        response.content_type = 'text/event-stream'
        response.set_header('Cache-Control', 'no-cache')

        pubsub = reds.pubsub()
        pubsub.subscribe('chat')
        for message in pubsub.listen():
            return 'data: %s\n\n' % message['data']

变成:

@get('/stream')
    def stream():
        response.content_type = 'text/event-stream'
        response.set_header('Cache-Control', 'no-cache')

        now = datetime.datetime.now().time().replace(microsecond=0)
        return  "data: %s\n\n"%now

这样就能正常工作,但这不是我需要的,因为这是一个返回当前时间(以毫秒为单位)的函数……

既然在Python命令行界面中没有问题,那这里到底出了什么错呢?我一直在想办法解决这个看似简单的问题……

1 个回答

1

哎呀!这个问题的解决办法其实很简单。

我需要把

def stream():
    pubsub = reds.pubsub()
    pubsub.subscribe('chat')
    for message in pubsub.listen():
        return 'data: %s\n\n' % message['data']

改成

def stream():
    pubsub = reds.pubsub()
    pubsub.subscribe('chat')
    for message in pubsub.listen():
        yield 'data: %s\n\n' % message['data']

简单来说,就是把 return 改成 yield。不过奇怪的是,最开始 yield 是不管用的……

撰写回答