浅谈前后端轮询sse、websocket+node

355 阅读5分钟

前后端轮询sse、websocket+node

第一种方式:前端原始轮询(缺点:性能差)
第二种方式:SSE——server send event(缺点:单工)
第三种方式:websocket协议 通过服务端推送数据到客户端
第四中方式:原生websocket会比较麻烦 使用 socket.io

以下是简单的例子

例子:为了实现数据不刷新实时更新,比如聊天实时接收

第一种方式:前端原始轮询(缺点:性能差)

前端原始轮询:

 setInterval(() => {
    // 客户端不断发送请求 前端轮询,性能太差,不停占用网络请求
    render()
 })

第二种方式:SSE——server send event(缺点:单工)

Server-sent events:使用server-sent 事件的方法,服务器可以在任何时刻向我们的web页面推送数据和信息.这些被推送进来的信息可以在这个页面上作为事件+data来处理.

服务端定时向客户端发送数据,单工,单向

readyState 代表连接状态:

        0 CONNECTING (0)
        1 OPEN (1)
        2 CLOSED(2)
前端html:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <h2 class="exchange"></h2>
    <script>
        let source = new EventSource('/sse')

        source.onopen = function() {

            // readyState  0:正在连接  1: 连接成功 2:连接失败

            console.log('连接成功。。。', source.readyState)

        }

        source.onmessage = function(e) {

            console.log('获取到的数据是:',e.data)

            document.querySelector('.exchange').innerHTML = e.data

        }

        source.onerror = function(err) {

            console.log(err)

        }
    </script>
</body>
</html>
后端:

服务端设置

设置头部:"Content-type","text/event-stream"

返还数据格式:

data:声明数据开始

\r\n\r\n标志数据结尾
const http = require("http")

const fs = require('fs')

let server = http.createServer((req,res) => {

    let url = req.url

    if(url == '/') {

       let resData =  fs.readFileSync('index.html')

       res.end(resData)

    } else if(url == '/sse') {

  // 修改头部信息以流的方式进行推送

        res.setHeader('content-type','text/event-stream;charset=utf-8')

        // 服务端定时推送数据到客户端

        setInterval(() => {

            // 注意传递的数据收尾要加  data:  \r\n\r\n  这样前端才能截取到数据

            res.write('data:时间是:' + new Date()+'\r\n\r\n')

        }, 1000);

    }

    // res.write()

})

server.listen(4000)

第三种方式:websocket协议 通过服务端推送数据到客户端

WebSocketHTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议;

1.创建websocket服务器;
var WebSocketServer = require('ws').Server, 
wss = new WebSocketServer({ port: 8181 }); 
wss.on('connection', function (ws) {    
    console.log('client connected');   
    ws.on('message', function (message) {       
        //监听接收的数据        
        console.log(message);    
    });   
    setInterval(() => {       
        let somedata = {            
            name:"张三",            
            age:20        
        }       
        ws.send(JSON.stringify(somedata));    
    }, 1000); 
});
2.客户端代码
2-1.建立握手
var ws = new WebSocket("ws://localhost:8181");

打开协议:ws.onopen = function () {}
2-2.发送数据到服务端
ws.send("客户端数据");
2-3.关闭协议:关闭协议后不能发送数据
ws.close();
2-4.接收消息
ws.onmessage = function(e){        
    // console.log(e.data);
}
服务端:
var WebSocketServer = require('ws').Server, // 依赖ws模块:webSocketServer简写

wss = new WebSocketServer({ port:8181 });

wss.on('connection', function(ws) {

    console.log('客户端连接')

    ws.on('message', function(message) {

        // 监听接收的数据

        console.log('11'+ message)

    })

    setInterval(() => {

        let somedata = {

            name: 'zyj',

            age: 18

        }

        ws.send(JSON.stringify(somedata)) // stringify 转换成JSON

    }, 1000)

})

客户端:
<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <title>Document</title>

</head>

<body>

    <button onclick="sub()">点击我发送数据给服务端</button>

    <script>

        var ws = new WebSocket("ws://localhost:8181")

        ws.onopen = function() {

            console.log('前端连接成功')

        }

        ws.onmessage = function(e) {

            console.log(JSON.parse(e.data))

        }

        function sub() {

            ws.send('发送到服务端的数据')

        }

    </script>

</body>

</html>

第四中方式:原生websocket会比较麻烦 使用 socket.io

socket.io模块
服务端
const server = require('http').createServer(app.callback()); 
const io = require('socket.io')(server); 
server.listen(3000);
客户端
let socket = io.connect(); 
this.emit("clientfn","hello i am client");
socket.on("message",function(data){}

完整代码:

服务端:
const Koa = require('koa')

const static = require('koa-static')

const Router = require('koa-router')

let app = new Koa()

let router = new Router()

app.use(static(__dirname + '/static'))

const server = require('http').createServer(app.callback())

// 用socket.io执行server

const io = require('socket.io')(server)

// 普通的服务器

router.get('/', ctx => {

    ctx.body = 'dddddd'

})

app.use(router.routes())

// socket服务器,,有连接socket就会打印

io.on('connection', (socket) => {

    console.log('有socket连接')

    socket.on("testFn", function(data) {

        console.log(data)

        // 1.只发送给一个用户

        // socket.emit("clientFn", "我是服务端发来的数据")

        // 2.广播给所有,除了自己之外的所有客户

        setTimeout(() => {

          socket.broadcast.emit('clientFn', "我是服务端发来的数据-broadcast")

        })

    })

    // 服务端接受客户端on
    socket.on('addData', function(data) {
        // 服务端发送服务端broadcast.emit
        socket.broadcast.emit('addInputData', data)

    })
})

server.listen(3000)
客户端:
<!DOCTYPE html>

<html lang="en">

<head>

    <meta charset="UTF-8">

    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <meta http-equiv="X-UA-Compatible" content="ie=edge">

    <script src="socket.io.js" type="text/javascript"></script>

    <title>文章信息展示</title>

    <style>

        body {

            margin: 0;

        }

        ul {

            margin: 0;

            padding: 0;

            list-style: none;

        }

        a {

            text-decoration: none;

            color: #404040;

        }

        .wrap{

            width: 600px;

            margin: 0 auto;

        }

        .news-list {

            width: 600px;

        }

        .news {

            width: 100%;

            display: flex;

            justify-content: space-between;

            padding: 15px 0;

            border-bottom: 1px solid #999;

        }

        .info {

            display: flex;

            width: 170px;

            justify-content: space-between;

            font-size: 12px;

            color: #888;

        }

        .tips {

            display: flex;

            width: 100px;

            justify-content: space-between;

        }

        .news-list li:nth-child(5) {

            border-bottom: none;

        }

        .pagination{

            display: flex;

            width: 210px;

            text-align: center;

            background-color: rgb(252, 238, 238);

            border-radius: 25px;

            overflow: hidden;

            margin: 0 auto;

            justify-content: center;

        }

        .pagination a{

            width: 30px;

            line-height: 30px;

            color: #404040;

        }

        .pagination a:nth-child(1) {

            transform: rotate(-45deg) ;

        }

        .next {

            transform: rotate(45deg) ;

        }

        .pagination a:hover{

            color: rgb(247, 73, 73);

        }

        .news div{

            width:420px;

        }

        /* 聊天框样式 */

        .message-box{

            width: 320px;

            height: 480px;

            border: 1px solid;

            position: fixed;

            bottom: 20px;

            right: 10px;

            background: white;

            border-radius: 10px;

            overflow: hidden;

        }

        .message-header{

            width: 100%;

            height: 40px;

            background: rgb(0,175,242);

            text-align: center;

            line-height: 40px;

            color: white;

        }

        .input-text{

            position:absolute;

            bottom: 0px;

        }

        .input-text textarea{

            width: 300px;

            margin-left: 10px;

            margin-bottom: 20px;

            height: 100px;

        }

        .input-text button{

            float:right;

            margin-right: 10px;

            margin-bottom: 20px;

        }

        .chat-show{

            height: 200px;

            margin-top:20px;

        }

        .chat-show li{

            margin: 10px;            

        }

        .chat-left{

            /* float: left; */

            text-align: left;

        }

        .chat-right{

            text-align: right;

        }

        ul{

            overflow:scroll;

        }

    </style>

</head>

<body>
    <div class="wrap">

        <ul class="news-list">
          <li class="news">

                <a href="javascript:;">

                    <img src="./img/img.png" alt="">

                </a>

                <div>

                    <h3>

                        <a href="javascript:;">标题标题标题标题</a>

                    </h3>

                    <div class="info">

                        <span class="tips"><span>tips</span></span>

                        <!-- <span class="line"></span> -->

                        <span class="time">| &nbsp;&nbsp;1小时前</span>

                    </div>

                </div>

            </li>  

            <li class="news">

                <a href="javascript:;">

                    <img src="./img/img.png" alt="">

                </a>

                <div>

                    <h3>

                        <a href="javascript:;">标题标题标题标题</a>

                    </h3>

                    <div class="info">

                        <span class="tips"><span>tips</span></span>

                        <!-- <span class="line"></span> -->

                        <span class="time">| &nbsp;&nbsp;1小时前</span>

                    </div>

                </div>

            </li>   
             <li class="news">

                <a href="javascript:;">

                    <img src="./img/img.png" alt="">

                </a>

                <div>

                    <h3>

                        <a href="javascript:;">标题标题标题标题</a>

                    </h3>

                    <div class="info">

                        <span class="tips"><span>tips</span></span>

                        <!-- <span class="line"></span> -->

                        <span class="time">| &nbsp;&nbsp;1小时前</span>

                    </div>

                </div>

            </li>  
             <li class="news">

                <a href="javascript:;">

                    <img src="./img/img.png" alt="">

                </a>

                <div>

                    <h3>

                        <a href="javascript:;">标题标题标题标题</a>

                    </h3>

                    <div class="info">

                        <span class="tips"><span>tips</span></span>

                        <!-- <span class="line"></span> -->

                        <span class="time">| &nbsp;&nbsp;1小时前</span>

                    </div>

                </div>

            </li>  
             <li class="news">

                <a href="javascript:;">

                    <img src="./img/img.png" alt="">

                </a>

                <div>

                    <h3>

                        <a href="javascript:;">标题标题标题标题</a>

                    </h3>

                    <div class="info">

                        <span class="tips"><span>tips</span></span>

                        <!-- <span class="line"></span> -->

                        <span class="time">| &nbsp;&nbsp;1小时前</span>

                    </div>

                </div>

            </li>  
             <li class="news">

                <a href="javascript:;">

                    <img src="./img/img.png" alt="">

                </a>

                <div>

                    <h3>

                        <a href="javascript:;">标题标题标题标题</a>

                    </h3>

                    <div class="info">

                        <span class="tips"><span>tips</span></span>

                        <!-- <span class="line"></span> -->

                        <span class="time">| &nbsp;&nbsp;1小时前</span>

                    </div>

                </div>

            </li>  

        </ul>

        <div class="pagination">

            <a href="javascript:;" class="prev"></a>

            <a href="javascript:;">1</a>

            <a href="javascript:;">2</a>

            <a href="javascript:;">3</a>

            <a href="javascript:;">4</a>

            <a href="javascript:;">5</a>

            <a href="javascript:;" class="next"></a>

        </div>

    </div>

    <!-- 聊天框模板 -->

    <div class="message-box">

            <div class="message-header">聊天框</div>

            <ul class="chat-show">

                <!-- <li class="chat-left">A:大家好</li>

                <li class="chat-right">B:你好啊</li>

                <li class="chat-left">A:你好啊</li>

                <li class="chat-right">B:很高兴见到大家</li>

                <li class="chat-left">B:哈哈</li>

                <li class="chat-left">B:哈哈</li>

                <li class="chat-left">B:哈哈</li>

                <li class="chat-left">B:哈哈</li>

                <li class="chat-left">B:哈哈</li> -->

            </ul>

            <form class="input-text" onsubmit="return false;">

                <textarea class="input-frame" ></textarea>

                <button type="submit" class="btn">发送</button>

            </form>

        </div>

</body>
<script> 

    // 因为同源是相对地址,直接写‘/’,不是的话需要加http://

    // 同源非同源都支持

    let socket = io.connect('/')

    socket.emit("testFn", "我是客户端发送的内容..")

    socket.on('clientFn', function(data) {

        console.log('接受客户端的数据:' + data)

    })

    document.querySelector('.btn').onclick = function() {

        // 客户端发送给服务端

        let val = document.querySelector('.input-frame').value

        socket.emit("addData", val)

        let ul = document.querySelector('.chat-show')

        let li = document.createElement('li')

        li.innerHTML = val

        li.classList.add('chat-right')

        ul.appendChild(li)

    }

    socket.on('addInputData', function(data) {

        // 客户端接受服务端

        let ul = document.querySelector('.chat-show')

        let li = document.createElement('li')

        li.innerHTML = data

        li.classList.add('chat-left')

        ul.appendChild(li)

    })

</script>
</html>