This is an automated email from the ASF dual-hosted git repository.

liubao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-docs.git


The following commit(s) were added to refs/heads/master by this push:
     new 9fc2984  add websockets (#347)
9fc2984 is described below

commit 9fc29849bac591570049bf531d04b6e5356d8903
Author: liubao68 <[email protected]>
AuthorDate: Sat Jul 27 15:56:03 2024 +0800

    add websockets (#347)
---
 .../zh_CN/docs/featured-topics/secrets.md          |   1 +
 .../docs/featured-topics/secrets/websocket.md      | 199 +++++++++++++++++++++
 2 files changed, 200 insertions(+)

diff --git a/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md 
b/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md
index 3b092a4..84c317b 100644
--- a/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md
+++ b/java-chassis-reference/zh_CN/docs/featured-topics/secrets.md
@@ -13,3 +13,4 @@
 * [Java Chassis 3技术解密:接口维度负载均衡](secrets/load-balancer-operation.md)
 * [Java Chassis 3技术解密:实用的可观测性](secrets/observability.md)
 * [Java Chassis 3技术解密:流式响应和人工智能应用开发](secrets/sse.md)
+* [Java Chassis 3技术解密:WebSocket和人工智能应用开发](secrets/websocket.md)
diff --git 
a/java-chassis-reference/zh_CN/docs/featured-topics/secrets/websocket.md 
b/java-chassis-reference/zh_CN/docs/featured-topics/secrets/websocket.md
new file mode 100644
index 0000000..1dd4e20
--- /dev/null
+++ b/java-chassis-reference/zh_CN/docs/featured-topics/secrets/websocket.md
@@ -0,0 +1,199 @@
+# Java Chassis 3技术解密:WebSocket和人工智能应用开发
+
+前一篇《Java Chassis 3技术解密:流式响应和人工智能应用开发》解密了Java Chassis 
3使用流式响应和SSE开发人工智能应用的功能。为了获取更好的用户体验和提升人工智能后台资源调度效率,WebSocket的双向通信特征在人工智能场景也经常被采用。
+
+以最常见的知识问答为例:当用户输入一段文本,人工智能会逐段生成应答,用户根据结果,提出新的问题和发表疑问,人工智能根据新的信息重新计算应答。在一些复杂的对话场景,人工智能的响应可能被打断,需要根据用户的输入时刻对处理结果进行调整。
 
+
+人工智能的处理后台需要保留用户会话上下文,并针对该会话合理调度处理资源和缓存会话信息。 
+
+Java Chassis 3提供了非常简洁的WebSocket支持,满足上述场景对于微服务开发框架功能的要求。
+
+## 使用WebSocket
+
+首先,看看微服务架构下一个简单的调用场景。
+
+      前端(浏览器) -> 应用网关(edge service) -> 消费者微服务 -> 提供者微服务
+
+* 提供者微服务:定义WebSocket服务和响应用户请求
+
+定义WebSocket非常简单,只需要使用 `Transport` 标签声明接口方法为 `WEBSOCKET` ,参数使用 
`ServerWebSocket`。
+
+```java
+@RestSchema(schemaId = "WebsocketController")
+@RequestMapping(path = "/ws")
+public class WebsocketController {
+  @PostMapping("/websocket")
+  @Transport(name = CoreConst.WEBSOCKET)
+  public void websocket(ServerWebSocket serverWebsocket) {
+    AtomicInteger receiveCount = new AtomicInteger(0);
+    serverWebsocket.writeTextMessage("hello", r -> {
+    });
+    serverWebsocket.textMessageHandler(s -> {
+      receiveCount.getAndIncrement();
+    });
+    serverWebsocket.closeHandler((v) -> System.out.println("closed"));
+    new Thread(() -> {
+      for (int i = 0; i < 5; i++) {
+        serverWebsocket.writeTextMessage("hello " + i, r -> {
+        });
+        try {
+          Thread.sleep(500);
+        } catch (InterruptedException e) {
+          e.printStackTrace();
+        }
+      }
+      serverWebsocket.writeTextMessage("total " + receiveCount.get());
+      serverWebsocket.close();
+    }).start();
+  }
+}
+```
+
+上述例子使用后台线程给消费者写入5条消息,并记录收取到的消息次数,最终写入收取到消息次数。 Open API并没有对双向流式通信做出规范定义,Java 
Chassis 3要求WebSocket的方法使用 `Post`。 
+
+`WebSocket`是一个新的 `Tranport`, 但是它直接构建于 `REST` 之上,因此底层实现复用了 `Rest Over Vert.x` 
通信协议,只需要在其上增加 `websocketEnabled` 和 `websocket-prefix`两个参数。 
需要注意Websocket接口定义的URL前缀需要和`websocket-prefix`保持一致。
+
+```yaml
+servicecomb:
+  rest:
+    address: 0.0.0.0:9094?websocketEnabled=true
+    server:
+      websocket-prefix: /ws
+```
+
+* 消费者微服务: 消费提供者WebSocket,并对外提供新的WebSocket服务
+
+消费者可以像调用普通REST接口一样调用WebSocket,开发起来非常简单。
+
+```java
+@RestSchema(schemaId = "ClientWebsocketController")
+@RequestMapping(path = "/ws")
+public class ClientWebsocketController {
+  interface ProviderService {
+    WebSocket websocket();
+  }
+
+  @RpcReference(schemaId = "WebsocketController", microserviceName = 
"provider")
+  private ProviderService providerService;
+
+  @PostMapping("/websocket")
+  @Transport(name = CoreConst.WEBSOCKET)
+  public void websocket(ServerWebSocket serverWebsocket) {
+    WebSocket providerWebSocket = providerService.websocket();
+    providerWebSocket.closeHandler(v -> serverWebsocket.close());
+    providerWebSocket.textMessageHandler(m -> {
+      System.out.println("send message " + m);
+      serverWebsocket.writeTextMessage(m);
+    });
+    serverWebsocket.textMessageHandler(m -> {
+      System.out.println("receive message " + m);
+      providerWebSocket.writeTextMessage(m);
+    });
+  }
+}
+```
+
+上述代码消费提供者的WebSocket服务,实现将前端的消息写给提供者,并将提供者的消息返回给前端。 和提供者微服务一样,也需要在配置文件增加 
`websocketEnabled` 和 `websocket-prefix`两个参数。
+
+* 应用网关:透明转发
+
+应用网关无需开发代码,可以实现透明转发,只需要在配置文件里面启用WebSocket和设置路由信息。 
+
+```yaml
+servicecomb:
+  rest:
+    address: 0.0.0.0:9090?websocketEnabled=true
+    server:
+      websocket-prefix: /ws
+
+  http:
+    dispatcher:
+      edge:
+        websocket:
+          mappings:
+            consumer:
+              prefixSegmentCount: 0
+              path: "/ws/.*"
+              microserviceName: consumer
+              versionRule: 0.0.0+
+```
+
+上述代码将前端 `/ws/.*` 路径下的WebSocket请求转发给后端的 `consumer` 服务。 
+
+* 前端(浏览器):消费WebSocket
+
+大部分浏览器都支持通过 `WebSocket` 与后端交互。下面是简单的代码片段:
+
+```javascript
+<!DOCTYPE html> 
+<meta charset="utf-8" /> 
+<title>WebSocket Test</title> 
+<script language="javascript"type="text/javascript"> 
+    var wsUri ="ws://localhost:9090/ws/websocket";
+    var output; 
+     
+    function init() {
+        output = document.getElementById("output");
+        testWebSocket();
+    } 
+  
+    function testWebSocket() {
+        websocket = new WebSocket(wsUri);
+        websocket.onopen = function(evt) {
+            onOpen(evt)
+        };
+        websocket.onclose = function(evt) {
+            onClose(evt)
+        };
+        websocket.onmessage = function(evt) {
+            onMessage(evt)
+        };
+        websocket.onerror = function(evt) {
+            onError(evt)
+        };
+    } 
+  
+    function onOpen(evt) {
+        writeToScreen("CONNECTED");
+        doSend("WebSocket rocks");
+    } 
+  
+    function onClose(evt) {
+        writeToScreen("DISCONNECTED");
+    } 
+  
+    function onMessage(evt) {
+        writeToScreen('<span style="color: blue;">RESPONSE: '+ 
evt.data+'</span>');
+        doSend(evt.data);
+    } 
+  
+    function onError(evt) {
+        writeToScreen('<span style="color: red;">ERROR:</span> '+ evt.data);
+    } 
+  
+    function doSend(message) {
+        writeToScreen("SENT: " + message); 
+        websocket.send(message);
+    } 
+  
+    function writeToScreen(message) {
+        var pre = document.createElement("p");
+        pre.style.wordWrap = "break-word";
+        pre.innerHTML = message;
+        output.appendChild(pre);
+    } 
+  
+    window.addEventListener("load", init, false); 
+</script> 
+<h2>WebSocket Test</h2> 
+<div id="output"></div> 
+</html>
+```
+
+上述代码将收取到的消息打印在控制台,并将消息写回服务器。 
+
+## WebSocket、SSE、Long/Short Polling
+
+WebSocket、SSE、Long/Short 
Polling都被应用于人工智能场景,它们都有各自的优点和适用场景。WebSocket可以提供最好的用户体验,但是在扩容、大规模并发方面会面临问题。Long/Short
 Polling可以提供更好的扩展性和可靠性,但是开发难度大,用户体验差。 SSE是两者非常好的权衡。 
+
+> 在 `小艺` 
人工智能应用中,为了提供更好的交互体验和提升后端资源调度能力,需要选择WebSocket。WebSocket在整个应用系统中使用的比例并不高,为了部分场景引入一个新的技术,开发和维护成本非常高。Java
 Chassis 3 的WebSocket功能具备和普通RPC/REST接口一样简单的开发体验,能够帮助开发团队提升开发效率和降低维护成本。 

Reply via email to