前后端轮询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协议 通过服务端推送数据到客户端
WebSocket
是 HTML5
开始提供的一种在单个 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">| 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">| 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">| 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">| 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">| 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">| 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>