使用服务器发送的事件和EventSource

时间:2019-03-16 17:09:19

标签: graphql server-sent-events eventsource

我正在考虑使用服务器发送的事件作为支持api实现“订阅”类型。

我正在苦苦挣扎的是接口,更确切地说,是该操作的http层。

问题:

使用本地EventSource不支持:

  1. 指定HTTP方法,默认情况下使用“ GET”。
  2. 包括有效负载(GraphQL查询)

虽然#1不可辩驳,但可以使用查询参数规避#2。

查询参数的上限为〜2000个字符(可以争论) 仅仅依靠他们的感觉太脆弱了。

我正在考虑的解决方案是为每个可能的事件创建一个专用的端点。

例如:事件的URI,代表双方之间已完成的交易:

/graphql/transaction-status/$ID

将在服务器中转换为以下查询:

subscription TransactionStatusSubscription {
    status(id: $ID) {
        ready
    }
}

此方法的问题是:

  1. 要添加为每个URI到GraphQL转换创建处理程序。
  2. 部署服务器的新版本
  3. GraphQL提供的灵活性丧失->客户端应控制查询
  4. 跟踪代码库中的所有端点(后端,前端,移动)

我可能还缺少更多的问题。

也许您能想到一种更好的方法? 一个会允许使用EventSource提供请求有效载荷的更好方法吗?

3 个答案:

答案 0 :(得分:3)

如果您使用的是Apollo,则它们支持automatic persisted queries(在文档中为APQ的缩写)。如果您不使用Apollo,则任何语言的实现都应该不错。我建议您遵循他们的约定,以便您的客户可以根据需要使用Apollo。

任何客户端第一次使用查询的哈希值发出EventSource请求时,都会失败,然后将具有完整有效负载的请求重试到常规GraphQL端点。如果在服务器上启用了APQ,则所有具有查询参数的客户端的后续GET请求都将按计划执行。

解决了该问题后,只需为GraphQL进行服务器发送的事件传输(考虑returns an AsyncIteratorsubscribe函数就很容易了)

我正在公司中考虑这样做,因为一些前端开发人员喜欢EventSource的处理方式。

答案 1 :(得分:1)

GraphQL中的订阅通常使用WebSockets而非SSE实现。 Apollo和Relay均支持使用subscriptions-transport-ws客户端侦听事件。 Apollo Server包括built-in support,用于使用WebSocket进行订阅。如果您只是尝试实现订阅,则最好使用这些现有解决方案之一。

也就是说,这里有一个利用SSE订阅here的库。看起来似乎已经不再维护它了,但是如果您打算使SSE正常运行,则可以在源代码中四处摸索,以获取一些想法。从源头上看,作者似乎通过用返回请求ID的POST请求初始化每个订阅来解决了上面提到的局限性。

答案 2 :(得分:1)

这里有两件事在起作用:SSE连接和GraphQL端点。端点具有要遵循的规范,因此仅从订阅请求返回SSE不会完成,并且仍然需要GET请求。所以两者必须分开。

如何让客户通过/graphql-sse打开SSE频道,这会创建频道令牌。然后,客户端可以使用此令牌请求订阅,事件将通过选定的渠道到达。

令牌可以作为SSE通道上的第一个事件发送,并将令牌传递给查询,可以由客户端在Cookie,请求标头甚至是未使用的查询变量中提供。

或者,服务器可以将最后打开的通道存储在会话存储中(将客户端限制为单个通道)。

如果未找到通道,则查询失败。如果通道关闭,则客户端可以再次打开它,然后在查询字符串/ cookie / header中传递令牌,或者让会话存储对其进行处理。