背景

最近在调研 Web 前端如何可以和后端进行双向的通信,这其实是个非常有价值的话题,或者说是个非常难且不断被提及的话题。

例如在网络质量差的得情况下,如果还是用原始的请求响应模型,那么对于前端的用户体验是极差的,尤其是现在很多 SPA 的情况下,API 的即时性更为重要。除了网络差的情况,后端也有推送的需求,例如前端请求了一个非常耗时的请求,很多时候这种需求都会做成异步的,那么就有了等 Server 侧完成处理之后通知前端的需求,当然,你也可以让前端 polling 去查询结果,但是这个对前端的编码和用户体验都是不友好的。

所以,基于这些背景,我就调研前端和后端目前有哪些可能的技术方案选型,能够更好地支持业务的开发,但是好像结果还是比较不理想,也就有 websocket 这么一项,有可能我没有注意到一些更新的技术,如果你有相关的资料,欢迎留言交流一下。

http2 push

不再支持了。

SSE(Server Send Events)

  1. const evtSource = new EventSource("/v1/stream/topic");
  2. evtSource.onmessage = function(event) {
  3. // handle event
  4. }

感受:

Streaming API

总结:做不到同时发送和同时接收;
可以做到:

websocket

总结:可以做到同时发送和同时接收

grpc web

截止到目前为止,gRPC Web 只支持两种类型的调用,分别是:

但是,并不是说你可以直接用 gRPC Web 直接调用一个普通的其他语言的 gRPC Server,因为他们协议是不一样的,所以中间需要一个 gRPC Web 代理,官方推荐的就是 Envoy,并且官方也将 Envoy 作为官方的实现方式进行迭代。

实现的原理:请求是通过 HTTP Post 请求发起的,然后被后端的 Envoy 接收,然后转换成通用的 gRPC 协议;然后在收到响应之后,然后再转换成 Post 的响应,但是 Post 的响应是一个编码后的字符串,还需要进行解码,这个在前端通过 gRPC Web 库实现。

扩展思路

XHR + chunked response

  1. var last_index = 0;
  2. var xhr = new XMLHttpRequest();
  3. xhr.open("GET", "/servers/scan");
  4. xhr.onprogress = function () {
  5. var curr_index = xhr.responseText.length;
  6. if (last_index == curr_index) return;
  7. var s = xhr.responseText.substring(last_index, curr_index);
  8. last_index = curr_index;
  9. console.log("PROGRESS:", s);
  10. };
  11. xhr.send();

一些过程资料

结论:无阻碍双向通信还是只有 websocket。