我正在考虑使用服务器发送的事件作为支持api实现“订阅”类型。
我正在苦苦挣扎的是接口,更确切地说,是该操作的http层。
问题:
使用本地EventSource不支持:
虽然#1不可辩驳,但可以使用查询参数规避#2。
查询参数的上限为〜2000个字符(可以争论) 仅仅依靠他们的感觉太脆弱了。
我正在考虑的解决方案是为每个可能的事件创建一个专用的端点。
例如:事件的URI,代表双方之间已完成的交易:
/graphql/transaction-status/$ID
将在服务器中转换为以下查询:
subscription TransactionStatusSubscription {
status(id: $ID) {
ready
}
}
此方法的问题是:
我可能还缺少更多的问题。
也许您能想到一种更好的方法? 一个会允许使用EventSource提供请求有效载荷的更好方法吗?
答案 0 :(得分:3)
如果您使用的是Apollo,则它们支持automatic persisted queries(在文档中为APQ的缩写)。如果您不使用Apollo,则任何语言的实现都应该不错。我建议您遵循他们的约定,以便您的客户可以根据需要使用Apollo。
任何客户端第一次使用查询的哈希值发出EventSource请求时,都会失败,然后将具有完整有效负载的请求重试到常规GraphQL端点。如果在服务器上启用了APQ,则所有具有查询参数的客户端的后续GET请求都将按计划执行。
解决了该问题后,只需为GraphQL进行服务器发送的事件传输(考虑returns an AsyncIterator的subscribe
函数就很容易了)
我正在公司中考虑这样做,因为一些前端开发人员喜欢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中传递令牌,或者让会话存储对其进行处理。