express-ws实现webSocket通信
前言
最近要给自己写的项目中加一个客服聊天的功能。就是前端商城和后台管理系统通信。但是是两个不同的端口。
百度了一下就找到了webSocket。
什么是webSocket?
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。(来自菜鸟教程:https://www.runoob.com/html/html5-websocket.html)
express-ws实现
1、首先在express项目中安装express-ws
npm i express-ws --save
2、然后引入
const express = require('express')
const app = express()
// 引入WebSocket
const ws = require("express-ws")
// 将webSocket服务混入app,相当于为app添加.ws方法
ws(app)
3、启动服务
//为了获取到所以的客户端
const wss = ws(app).getWss('/')
// 建立webSocket服务
app.ws('/', (ws, req) => {
console.log("连接成功!");
// send给客户端发消息
// on是监听事件
// message表示服务端传来的数据
ws.on("message", (msg) => {
// 给所有的客户端广播消息
wss.clients.forEach((e) => {
e.send(msg)
})
})
// close 事件表示客户端断开连接时执行的回调函数
ws.on('close', function (e) {
console.log('close connection')
})
})
app.listen(3002, () => {
console.log('success in port 3002,服务已经跑起来啦');
})
此时服务已经在3002端口跑起来了
前端接收消息
1、vue中
<script>
//连接webSocket
const ws = new WebSocket('ws://localhost:3002')
export default {
data () {
return {
msg: '',
msgList: []
}
},
mounted () {
// 绑定webSocket事件
//连接成功的回调
ws.addEventListener('open', this.handleWsOpen.bind(this), false)
//关闭的回调
ws.addEventListener('close', this.handleWsClose.bind(this), false)
//连接错误的回调
ws.addEventListener('error', this.handleWsError.bind(this), false)
//接收发送消息的回调
ws.addEventListener('message', this.handleWsMessage.bind(this), false)
},
methods: {
sendMessage () {
const currentY = new Date().getFullYear()
let currentM = new Date().getMonth() + 1
let currentD = new Date().getDate()
let currentH = new Date().getHours()
let currentMin = new Date().getMinutes()
let currentS = new Date().getSeconds()
if (currentM < 10) {
currentM = `0${currentM}`
}
if (currentD < 10) {
currentD = `0${currentD}`
}
if (currentH < 10) {
currentH = `0${currentH}`
}
if (currentMin < 10) {
currentMin = `0${currentMin}`
}
if (currentS < 10) {
currentS = `0${currentS}`
}
const date = `${currentY}-${currentM}-${currentD} ${currentH}:${currentMin}:${currentS}`
const name = window.sessionStorage.getItem('nickname')
const msg = JSON.stringify({
msg: this.msg,
name: name,
date: date,
left: true
})
ws.send(msg)
// 发送完清空聊天框
this.msg = ''
},
handleWsOpen () {
console.log('聊天已经启动!')
},
handleWsClose () {
console.log('聊天已经关闭!')
},
handleWsError () {
console.log('聊天出错!')
},
// 收发消息
handleWsMessage (e) {
console.log(e)
const msg = JSON.parse(e.data)
this.msgList.push(msg)
}
}
}
</script>
2、react中
const ws = new WebSocket('ws://localhost:3002')
class Chat extends Component {
constructor(props) {
super(props)
this.state = {
msg: "",
msgList:[]
}
}
componentDidMount () {
ws.addEventListener('open', this.handleWsOpen.bind(this), false)
ws.addEventListener('close', this.handleWsClose.bind(this), false)
ws.addEventListener('error', this.handleWsError.bind(this), false)
ws.addEventListener('message', this.handleWsMessage.bind(this), false)
}
sendMessage = ()=> {
const currentY = new Date().getFullYear()
let currentM = new Date().getMonth() + 1
let currentD = new Date().getDate()
let currentH = new Date().getHours()
let currentMin = new Date().getMinutes()
let currentS = new Date().getSeconds()
if (currentM < 10) {
currentM = `0${currentM}`
}
if (currentD < 10) {
currentD = `0${currentD}`
}
if (currentH < 10) {
currentH = `0${currentH}`
}
if (currentMin < 10) {
currentMin = `0${currentMin}`
}
if (currentS < 10) {
currentS = `0${currentS}`
}
const date = `${currentY}-${currentM}-${currentD} ${currentH}:${currentMin}:${currentS}`
const name = "客服"
const msg = JSON.stringify({
msg: this.state.msg,
name: name,
date: date,
left: false
})
ws.send(msg)
// 发送完清空聊天框
this.setState({
msg:""
})
}
handleWsOpen () {
message.success("连接成功")
}
handleWsClose () {
message.info("聊天结束")
}
handleWsError () {
message.error("连接失败")
}
// 收发消息
handleWsMessage (e) {
const msg = JSON.parse(e.data)
let arr = this.state.msgList
arr.push(msg)
this.setState({
msgList:arr
})
}
render () {
const msgList = this.state.msgList
return (
<Content
className="site-layout-background"
>
<div className="chatBox">
<div className="chat">
{/* 展示消息 */}
<div className="chat-info">
{msgList.map((item, k) => {
return <div className="info-detail">
<div className={item.left?'head-a':'head'}>
<span className={item.left?'name-a':'name'}>{item.name}</span>
<span>{item.date}</span>
</div>
<div className={item.left?'info-main-a':'info-main'}>
<span>{item.msg}</span>
</div>
</div>
})
}
</div>
{/* 发送消息 */}
<div className="send-msg">
<Input value={this.state.msg} onChange={(e) => {
this.setState({
msg:e.target.value
})
}} placeholder="请输入..."
style={{ width: "350px", marginRight: "10px" }}
onPressEnter={() => {
this.sendMessage()
}}
>
</Input>
<Button type="primary" onClick={() => {
this.sendMessage()
}}>
发送
</Button>
</div>
</div>
</div>
</Content >
)
}
}
效果如下:
vue全部代码
<template>
<div class="chat">
<div class="chat-box">
<div class="chat-info">
<div class="info-detail" v-for="(item,k) in msgList" :key="k">
<div :class="item.left?'head':'head-a'">
<span class="name">{{item.name}}</span>
<span>{{item.date}}</span>
</div>
<div :class="item.left?'info-main':'info-main-a'">
<span>{{item.msg}}</span>
</div>
</div>
</div>
<div class="chat-message">
<el-input v-model="msg" placeholder="请输入内容" @keyup.enter.native="sendMessage" >
<el-button slot="append" type="primary" @click="sendMessage" >发送</el-button>
</el-input>
</div>
</div>
</div>
</template>
<script>
const ws = new WebSocket('ws://localhost:3002')
export default {
data () {
return {
msg: '',
msgList: []
}
},
mounted () {
// 绑定webSocket事件
ws.addEventListener('open', this.handleWsOpen.bind(this), false)
ws.addEventListener('close', this.handleWsClose.bind(this), false)
ws.addEventListener('error', this.handleWsError.bind(this), false)
ws.addEventListener('message', this.handleWsMessage.bind(this), false)
},
methods: {
sendMessage () {
const currentY = new Date().getFullYear()
let currentM = new Date().getMonth() + 1
let currentD = new Date().getDate()
let currentH = new Date().getHours()
let currentMin = new Date().getMinutes()
let currentS = new Date().getSeconds()
if (currentM < 10) {
currentM = `0${currentM}`
}
if (currentD < 10) {
currentD = `0${currentD}`
}
if (currentH < 10) {
currentH = `0${currentH}`
}
if (currentMin < 10) {
currentMin = `0${currentMin}`
}
if (currentS < 10) {
currentS = `0${currentS}`
}
const date = `${currentY}-${currentM}-${currentD} ${currentH}:${currentMin}:${currentS}`
const name = window.sessionStorage.getItem('nickname')
const msg = JSON.stringify({
msg: this.msg,
name: name,
date: date,
left: true
})
ws.send(msg)
// 发送完清空聊天框
this.msg = ''
},
handleWsOpen () {
console.log('聊天已经启动!')
},
handleWsClose () {
console.log('聊天已经关闭!')
},
handleWsError () {
console.log('聊天出错!')
},
// 收发消息
handleWsMessage (e) {
console.log(e)
const msg = JSON.parse(e.data)
this.msgList.push(msg)
}
}
}
</script>
<style lang="less" scoped>
.chat {
padding: 100px 300px 0 300px;
display: flex;
justify-content: center;
.chat-box{
margin-top: 20px;
padding: 10px 10px 10px 10px;
width: 400px;
height: 600px;
background-color: #fff;
border-radius: 10px 10px 0 0 ;
.chat-info{
height: 550px;
overflow: auto;
.info-detail{
margin-bottom: 5px;
.head{
width: 100%;
margin-bottom: 5px;
display:flex;
flex-direction: row-reverse;
.name{
margin-left: 5px;
color: rgb(240, 74, 74);
}
}
.head-a{
width: 100%;
margin-bottom: 5px;
.name{
margin-right: 5px;
color: rgb(22, 189, 240);
}
}
.info-main-a{
font-size: 18px;
font-family: 楷体;
}
.info-main{
font-size: 18px;
font-family: 楷体;
display:flex;
flex-direction: row-reverse;
}
}
}
.chat-message{
height: 50px;
}
}
}
</style>