0

我正在尝试为使用 python 中的服务器发送事件的用户构建实时通知系统。

我面临的问题是当我刷新浏览器时,这意味着浏览器将尝试再次点击 EventSource url,并且根据文档,它应该在下一个请求中将 event.lastEventId 作为标头的一部分发送。每次刷新页面时我都会得到无。

<!DOCTYPE html>
<html>
    <header><title>SSE test</title></header>
    <body>
        <ul id="list"></ul>
        <script>
        const evtSource = new EventSource("/streams/events?token=abc");
        evtSource.onmessage = function(event) {
            console.log('event', event)
            console.log('event.lastEventId', event.lastEventId)
            const newElement = document.createElement("li");
            const eventList = document.getElementById("list");
            newElement.innerHTML = "message: " + event.data;
            eventList.appendChild(newElement);
        }
        </script>
    </body>
</html>

在服务器端

from sse_starlette.sse import EventSourceResponse
from asyncio.queues import Queue
from starlette.requests import Request

@event_router.get(
"/streams/events",
status_code=HTTP_200_OK,
summary='',
description='',
response_description='')
async def event_stream(request: Request):
    return EventSourceResponse(send_events(request))


async def send_events(request: Request):
    try:
        key = request.query_params.get('token')
        last_id = request.headers.get('last-event-id')
        print('last_id ', last_id) # this value is always None

        connection = Queue()
        connections[key] = connection

        while RUNNING:
            next_event = await connection.get()
            print('event', next_event)
            yield dict(data=next_event, id=next_event['id'])
            connection.task_done()
    except asyncio.CancelledError as error:
        pass

现在,根据 SSE 上的每个文档,当客户端重新连接或刷新页面时,它将在标题中发送 last-event-id。我正在尝试使用 request.headers.get('last-event-id') 读取它,但这始终为空。

有关如何获取最后一个事件 ID 的任何指示都会有所帮助。另外,一旦用户看到事件,我将如何确保即使稍后我也不会发送相同的事件,因为我的整个逻辑将基于服务器接收到的 last-event-id,所以如果它在阅读后为 None Id 1 到 4 的事件,我如何确保在服务器中我不应该将这些发回,即使用户的 last-event-id 为空

.

添加浏览器快照

第一张图片显示浏览器正在接收事件。例如 {alpha: abc, id:4}

第二张图片显示收到的事件正确设置了 lastEventId。

在此处输入图像描述

在此处输入图像描述

4

1 回答 1

3

我认为这是一种错误的理解。您从哪里得到“当客户端重新连接或刷新页面时,它将在标头中发送最后一个事件 ID”的部分。

我的理解是最后一个 ID 是在重新连接时发送的。当您直接刷新页面时,这不会被视为断开连接和重新连接。您将完全重新启动整个页面,并从浏览器与服务器建立全新的 SSE 连接。请记住,例如,您的 SSE 是否有某个请求参数,这可能是由页面上的某些内容驱动的。您可以从同一个“页面”打开两个选项卡,但将不同的项目放入页面中,这会导致此请求参数在您的 SSE 中有所不同。它们完全是两个不同的 SSE 连接。一个不会影响另一个,只是如果你有太多浏览器可以达到最大连接限制。同样,如果您单击刷新,这就像正在创建一个新选项卡。这是一个全新的连接。

于 2020-08-28T19:21:25.293 回答