Skip to content

WebSocket 全双工通信与SSE轻量化实现

🕒 Published at:

WebSocket 全双工通信

HTML和JavaScript实现

html
<!DOCTYPE html>
<html>

<head>
    <title>Java后端WebSocket的Tomcat实现</title>
    <meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport' />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>

<body>
    Welcome<br /><input id="text" type="text" />
    <button onclick="send()">发送消息</button>
    <hr />
    <button onclick="closeWebSocket()">关闭WebSocket连接</button>
    <hr />
    <div id="message"></div>
</body>

<script type="text/javascript">
    var websocket = null;
    // 判断当前浏览器是否支持WebSocket
    if ('WebSocket' in window) {
        websocket = new WebSocket('wss://chatdoc.xfyun.cn/openapi/chat?appId=a8410989&timestamp=1697436017&signature=5FofcnYs9Zo5Be8bLxtdfzClRVA=');
    } else {
        alert('当前浏览器 Not support websocket');
    }

    // 连接发生错误的回调方法
    websocket.onerror = function () {
        setMessageInnerHTML("WebSocket连接发生错误");
    };

    // 连接成功建立的回调方法
    websocket.onopen = function () {
        setMessageInnerHTML("WebSocket连接成功");
    };

    // 接收到消息的回调方法
    websocket.onmessage = function (event) {
        let data = JSON.parse(event.data);
        console.log(event.data);
        if (data.code == 0) {
            if (data.content) {
                document.getElementById('message').innerHTML += data.content;
            }
        }
    };

    // 连接关闭的回调方法
    websocket.onclose = function () {
        setMessageInnerHTML("WebSocket连接关闭");
    };

    // 监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function () {
        closeWebSocket();
    };

    // 将消息显示在网页上
    function setMessageInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    // 关闭WebSocket连接
    function closeWebSocket() {
        websocket.close();
    }

    // 发送消息
    function send() {
        var message = document.getElementById('text').value;
        let json = {
            chatExtends: {
                wikiPromptTpl: "请将以下内容作为已知信息:\n<wikicontent>\n请根据以上内容回答用户的问题。\n问题:<wikiquestion>\n回答:",
                wikiFilterScore: 65,
                temperature: 0.5
            },
            fileIds: ["19c6ef823bf247f69da030c2bfa1cd2a"],
            messages: [
                {
                    "role": "user",
                    "content": message
                }
            ]
        };
        websocket.send(JSON.stringify(json));
    }
</script>

</html>

SSE 轻量化实现

HTML和JavaScript实现

html
<!DOCTYPE html>
<html>

<head>
    <title>SSE Example</title>
</head>

<body>
    <h1>SSE Example</h1>
    <div id="messages"></div>
    <script>
        let sseEventObj = new EventSource("https://www.duang.pro/api/v1.Xinghuoai/stream");

        // 事件监听
        sseEventObj.onopen = function () {
            console.log('SSE已成功打开');
        };

        sseEventObj.onerror = function (event) {
            console.warn('SSE连接断开', event);
        };

        // 接收到消息
        sseEventObj.onmessage = function (event) {
            console.log('SSE接收到消息:', event);
        };

        // 添加一个事件监听器,处理消息事件
        sseEventObj.addEventListener('chat', function (event) {
            const data = event.data; // 获取消息内容
            document.getElementById("messages").innerHTML += data + " ";
            console.log('Received message: ' + data);
            if (data == "Example") {
                sseEventObj.close();
            }
        });
    </script>
</body>

</html>

PHP服务器实现

php
public function stream() {
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');
    header('Connection: keep-alive');
    // 重点,必须要加
    header('X-Accel-Buffering: no');

    // 建立连接后,您可以输出初始化数据到客户端
    echo "event: sse_init\ndata: {}\n\n";
    flush();

    // 监听事件源,并输出实时事件
    $event = 'chat';
    $strings = array("Hello", "World", "This", "is", "an", "Example");

    foreach ($strings as $string) {
        $data = $string;

        // 输出事件到客户端
        echo "event: $event\ndata: $data\n\n";
        ob_flush();
        flush();
         // 休眠一段时间等待下次事件
        sleep(1);
    }
}