简体   繁体   English

带回调的外部API异步调用

[英]External API async call with callback

I use Angular with Spring for internal API communication. 我使用Angular和Spring进行内部API通信。 Now I need to call external api to get some data. 现在,我需要调用外部api来获取一些数据。 That external API provides callback feature, so I trigger call from Angular, call Spring rest method which, at the end, calls external API. 该外部API提供了回调功能,因此我触发了来自Angular的调用,调用了Spring rest方法,最后该方法调用了外部API。 On the other hand I get data on my callback methods (Spring rest also), but I dont know how to transfer those data back to Angular. 另一方面,我通过回调方法获取数据(也有Spring rest),但是我不知道如何将这些数据传输回Angular。

Is websocket the only option? websocket是唯一的选择吗?

If internal API calls are longer than the allowable client timeout, then you will need to find a WebSocket or WebSocket-like alternative . 如果内部API调用的时间超过了允许的客户端超时时间,那么您将需要找到一个WebSocket或类似WebSocket的替代方法 The alternative to WebSockets is to use long-polling (good example with source code here ), which is essentially having the client repeatedly make requests until the original task is completed and the data can be sent. WebSockets的替代方法是使用长轮询此处是带有源代码的一个很好的示例),它实质上是让客户端重复发出请求,直到完成原始任务并可以发送数据为止。 Either way, you'll need to use a pub/sub mechanism of some sort to handle multiple users, which is where things can get complicated. 无论哪种方式,您都需要使用某种pub / sub机制来处理多个用户,这会使事情变得复杂。

Pub/sub can be complicated and I don't have an example on-hand, but essentially you must (1) have the client subscribe to a channel using a unique identifier (you can do this with CometD via a service channel), (2) evaluate the response, (3) publish the response to the client's subscribed channel, and finally (4) close the channel when it's no longer in use. 发布/订阅可能会很复杂,并且我手边没有示例,但是从本质上讲,您必须(1)使用唯一标识符让客户端订阅频道 (您可以通过服务频道使用CometD进行此操作),( 2)评估响应,(3)将响应发布到客户端的订阅频道,最后(4)在不再使用该频道时将其关闭。

I've had some luck with CometD as a library to simplify pub/sub channel management, and it provides a good abstraction for asynchronous communication , although I haven't tried it with Spring and it might be heavy for what you want to do. 我对CometD作为一个简化发布/订阅频道管理的库感到很幸运,它为异步通信提供了很好的抽象 ,尽管我还没有在Spring上尝试过,对于您想做的事情可能很繁琐。

Another option that I'm less familiar with is to use Spring with STOMP . 我不太熟悉的另一个选择是将Spring与STOMP一起使用。 This seems to come recommended by others . 这似乎是别人推荐的 Spring does provide ways to send messages to single users using STOMP: Sending message to specific user on Spring Websocket Spring确实提供了使用STOMP向单个用户发送消息的方法: 在Spring Websocket上向特定用户发送消息

I'd recommend following the above STOMP example. 我建议遵循上面的STOMP示例。

Additional STOMP resources: 其他STOMP资源:

As a side note, throttling may be necessary here, too, as with any time that you can spawn long-running threads from clients. 附带说明一下,在任何时候只要您可以从客户端派生长时间运行的线程,也可能需要进行限制。


If you choose not to use STOMP or CometD, then a lighter solution could be to roll your own pub/sub for this single case using Spring's DeferredResult (as in Roger Hughes example ), tying the subscription request to the long-poll request via a UUID token, which might also be the session ID if you choose to disallow concurrent requests per user. 如果您选择不使用STOMP或CometD,那么一个更简单的解决方案是使用Spring的DeferredResult针对这种情况滚动您自己的pub / sub(如Roger Hughes的示例 ),将订阅请求与长轮询请求通过UUID令牌,如果您选择禁止每个用户的并发请求,它也可能是会话ID。 On subscription, the system can associate the request with a UUID and return this UUID to the client. 订阅后,系统可以将请求与UUID关联,然后将此UUID返回给客户端。 The client can then make long-poll requests (again, as in Roger Hughes example ) but with the UUID attached. 然后,客户端可以发出长时间轮询的请求(同样,如Roger Hughes的示例所示 ),但要附加UUID。 The server can wait until the request for the given UUID has completed and then return the result to the client via the client's active long-poll request. 服务器可以等到对给定UUID的请求完成后,再通过客户端的活动长轮询请求将结果返回给客户端。

Channel management (ie, request/UUID-tracking) can be done by clearing the channel on DeferredResult result retrieval and removing orphan channels with a separate thread acting as a GC -- or, perhaps better yet, automatically clearing orphan channels by removing them on DeferredResult completion/timeout if no active listeners exist. 可以通过清除DeferredResult结果检索中的通道并使用充当GC的单独线程删除孤立通道来完成通道管理(即请求/ UUID跟踪),或者可能更好的办法是,通过删除孤立通道来自动清除孤立通道如果没有活动的侦听器,则DeferredResult完成/超时。 If you opt for the latter option, you will want to make sure that the client won't have any delay between its long-poll requests so that the DeferredResult doesn't unintentionally complete with no listeners. 如果选择后一个选项,则将要确保客户端在其长时间轮询请求之间不会有任何延迟,以使DeferredResult不会在没有侦听器的情况下无意间完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM