

统一声明:
1.本站联系方式QQ:709466365 TG:@UXWNET 官方TG频道:@UXW_NET 如果有其他人通过本站链接联系您导致被骗,本站一律不负责! 2.需要付费搭建请联系站长QQ:709466365 TG:@UXWNET 3.免实名域名注册购买- 游侠云域名 4.免实名国外服务器购买- 游侠网云服务
先搞懂Websocket到底是啥,不然代码写了也白瞎
你可能会问:“不就是个通信协议吗?用HTTP不行吗?”我告诉你,之前我也是这么想的,直到踩了大雷才明白——Websocket和HTTP的区别,根本就是“打电话”和“发消息”的区别。我给你做了个对比表,一眼就能看明白:
特性 | HTTP | Websocket |
---|---|---|
连接方式 | 客户端主动请求,服务器响应后断开 | 客户端与服务器建立长连接,一直保持 |
通信方向 | 单向(客户端问→服务器答) | 双向(客户端和服务器都能主动发消息) |
延迟 | 高(需等待请求-响应周期) | 低(连接保持,消息即时发送) |
资源占用 | 高(频繁建立连接) | 低(一个连接复用到底) |
MDN Web Docs( Mozilla 开发的权威Web文档)明确说:“Websocket 是为了解决实时Web应用的需求而设计的,比如聊天室、实时游戏这类需要双向快速通信的场景。”我室友的美食社群,正好需要用户实时分享“哪家店出了新品”“排队人多不多”,用Websocket简直太合适了——消息发出去0.1秒内所有人都能收到,比微信还快。
你可能又会问:“那Websocket难学吗?”我告诉你,一点都不难,只要你会写点JS,就能跟着做。我去年学的时候,也就花了半天时间,从安装依赖到写出能跑的代码,关键是得把“长连接”“双向通信”这两个概念吃透。
手把手写Websocket聊天室代码,每一步都给你扒开讲
我用Node.js(后端)+ 原生JS(前端)来写,因为这俩是最常用、资料最多的组合,你学了之后换成其他语言(比如Python的websockets库、Java的Spring WebSocket)也能举一反三。
第一步:搭后端Websocket服务器(Node.js + ws库)
你得装Node.js(官网下载就行,选LTS版本),然后新建个文件夹,比如叫“websocket-chat”,打开终端输npm init -y
初始化项目,再装Websocket的依赖:npm install ws
——这个ws库是Node.js生态里最火的Websocket库,Node.js官方文档都推荐用它。
然后新建个server.js
文件,写后端代码。我给你贴代码,每一行都给你解释:
// 引入ws库,创建WebSocket服务器
const WebSocket = require('ws');
// 创建服务器实例,监听3000端口
const wss = new WebSocket.Server({ port: 3000 });
// 存储所有连接的客户端(后面广播消息要用)
const clients = new Set();
// 当有客户端连接时触发connection事件
wss.on('connection', (ws) => {
// 把新连接的客户端加入clients集合
clients.add(ws);
console.log('有新客户端连接啦!当前在线人数:', clients.size);
// 当收到客户端发的消息时触发message事件
ws.on('message', (message) => {
console.log('收到消息:', message.toString());
// 广播消息给所有客户端(包括发消息的人)
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) { // 确保客户端连接是打开的
client.send(message.toString());
}
}
});
// 当客户端断开连接时触发close事件
ws.on('close', () => {
clients.delete(ws);
console.log('客户端断开连接,当前在线人数:', clients.size);
});
// 处理连接错误
ws.on('error', (error) => {
console.error('连接错误:', error);
});
});
console.log('Websocket服务器启动啦,监听端口3000~');
我跟你说,这里有两个关键点你得注意:
client.readyState === WebSocket.OPEN
,不然要是客户端已经断开了,你还发消息,会报错。我之前没加这个判断,服务器日志里全是“无法发送消息给已关闭的连接”,后来加上就好了。第二步:写前端页面(原生JS,不用框架)
新建个index.html
文件,写前端代码。前端的逻辑很简单:建立Websocket连接,发送消息,接收消息,显示到页面上。代码给你贴出来:
Websocket聊天室
.chat-box { width: 500px; margin: 20px auto; }
.messages { height: 300px; border: 1px solid #ddd; padding: 10px; overflow-y: auto; }
.input-area { margin-top: 10px; display: flex; }
.input-area input { flex: 1; padding: 5px; }
.input-area button { padding: 5px 10px; margin-left: 10px; }
// 建立Websocket连接(注意地址要和后端一致)
const socket = new WebSocket('ws://localhost:3000');
const messagesDiv = document.getElementById('messages');
const messageInput = document.getElementById('messageInput');
const sendBtn = document.getElementById('sendBtn');
// 当连接成功建立时触发onopen事件
socket.onopen = () => {
addMessage('系统提示:连接成功,可以发消息啦!');
};
// 当收到服务器发的消息时触发onmessage事件
socket.onmessage = (event) => {
addMessage(event.data);
};
// 当连接断开时触发onclose事件
socket.onclose = () => {
addMessage('系统提示:连接断开了...');
// 这里可以加断开重连逻辑(比如3秒后重新连接)
setTimeout(() => {
window.location.reload(); // 简单的重连方式,刷新页面
}, 3000);
};
// 发送消息的点击事件
sendBtn.addEventListener('click', () => {
const message = messageInput.value.trim();
if (message) {
socket.send(用户:${message}
); // 加个前缀区分用户
messageInput.value = ''; // 清空输入框
}
});
// 按回车键发送消息(优化体验)
messageInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendBtn.click();
}
});
// 把消息添加到页面上的函数
function addMessage(text) {
const messageP = document.createElement('p');
messageP.textContent = text;
messagesDiv.appendChild(messageP);
// 自动滚动到最底部,方便看最新消息
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
这里我要跟你强调几个细节:
连接地址:前端的ws://localhost:3000
得和后端的端口一致,不然连不上。我之前帮朋友做的时候,他后端用了3001端口,前端写成3000,结果一直提示“连接失败”,查了半小时才发现端口错了。
断开重连:我在onclose事件里加了个setTimeout刷新页面,虽然简单,但能解决用户刷新页面或网络波动后的重连问题。你也可以写更优雅的重连逻辑,比如不刷新页面,重新new一个WebSocket实例,不过对新手来说,刷新页面已经够用来。
自动滚动:messagesDiv.scrollTop = messagesDiv.scrollHeight
——这个很重要!不然消息多了,用户得手动拉滚动条才能看到最新消息,体验特别差。我之前没加这个,室友说“每次发消息都得往下拉,太麻烦了”,加了之后他才满意。
第三步:跑起来试试,看看效果
现在,你打开终端,在websocket-chat
文件夹下输node server.js
启动后端服务器,然后用浏览器打开index.html
——你会看到“系统提示:连接成功,可以发消息啦!”。然后你再打开另一个浏览器窗口(或标签页),也打开index.html
,在其中一个窗口输入“今晚吃火锅不?”,点发送,另一个窗口马上就能收到消息——是不是超神奇?
我去年做的时候,第一次看到两个窗口实时同步消息,差点跳起来——终于搞定了!室友当时在旁边看着,说“这才像话嘛”,后来他把这个聊天室放到他的美食社群里,用户反馈“发消息比微信还快”,他还请我吃了顿火锅。
这些踩坑点你一定要注意,不然写好的代码也会翻车
我把去年做聊天室时踩过的坑,全给你列出来,帮你避坑:
跨域问题:如果你的前端和后端不在同一个域名(比如前端是http://localhost:5500
,后端是ws://localhost:3000
),会出现跨域错误。解决办法是在后端设置允许跨域——比如用ws库的话,可以加headers
配置:
javascript
const wss = new WebSocket.Server({
port: 3000,
headers: {
'Access-Control-Allow-Origin': '' // 允许所有域名跨域(开发环境用,生产环境要改具体域名)
}
});
心跳检测:有时候网络波动会导致连接“假死”——比如用户没关页面,但连接已经断了,发消息发不出去。解决办法是加心跳检测:后端每隔30秒给客户端发个“ping”,客户端收到后回复“pong”,如果后端没收到“pong”,就断开连接重新连。我之前没加这个,用户反馈“有时候发消息没反应,得刷新页面”,加了之后再也没出现过这个问题。
消息格式: 用JSON格式发消息,比如{ "username": "小明", "content": "今晚吃火锅", "time": "2024-05-20 18:00" }——这样方便处理复杂消息(比如昵称、时间、表情)。我之前用纯文本发消息,后来要加昵称的时候,得拆字符串,特别麻烦,换成JSON就简单多了。
你按我上面说的步骤做,绝对能写出能用的Websocket聊天室代码。要是碰到问题,比如连接不上、消息发不出去,你可以先检查这几点:后端服务器有没有启动?端口对不对?跨域有没有处理?要是还解决不了,欢迎在评论区告诉我,我帮你看看——毕竟我踩过的坑比你吃过的米饭还多!
对了,你要是想加更多功能,比如用户登录、表情、历史消息,也可以留言告诉我,我下次再写篇教程教你。现在赶紧去试代码吧,等你成功的好消息!
Websocket和HTTP有什么不一样?为什么聊天室要用Websocket?
Websocket和HTTP的区别其实像“打电话”和“发消息”——HTTP是客户端主动问、服务器答完就挂,单向通信,延迟高还费资源;Websocket是建立长连接,客户端和服务器都能主动发消息,双向通信,延迟低又省资源。
聊天室需要实时同步消息,比如你发“吃火锅不”,得让所有人立刻收到,用HTTP的话得每隔1秒问服务器有没有新消息,不仅延迟高,服务器还得处理一堆重复请求,而Websocket刚好解决这个问题,所以聊天室肯定选Websocket啊。
用Node.js搭Websocket后端必须用ws库吗?有没有其他选择?
不是必须,但ws库是Node.js生态里最常用的Websocket库,Node.js官方文档都推荐用它,安装简单、API也直观,新手入门特别合适。
当然也有其他选择,比如socket.io,它封装了更多功能(比如自动重连、房间管理),但对刚学Websocket的人来说,先把ws库吃透,再学其他库会更轻松。
前端写Websocket聊天室必须用框架吗?原生JS能不能搞定?
完全不用!文中的前端代码就是用原生JS写的,没有用React、Vue这些框架,步骤也很简单——建立连接、监听消息、发送消息,几个函数就搞定了。
原生JS写Websocket的好处是不用学框架语法,直接跟浏览器的Websocket API打交道,更能理解底层逻辑,新手跟着文中的代码一步步来,肯定能写出能跑的前端页面。
Websocket聊天室启动后,两个窗口发消息不同步是怎么回事?
首先检查后端有没有“存储客户端集合”的逻辑——比如文中用const clients = new Set()存所有连接的客户端,要是没这一步,服务器收到消息后没法广播给所有客户端,自然不同步。
再看看广播消息的代码有没有写对,比如有没有循环clients集合,有没有判断client.readyState === WebSocket.OPEN,要是没判断连接状态,断开的客户端会收不到消息,也会导致不同步。
Websocket聊天室遇到跨域错误怎么办?
跨域一般是因为前端和后端的域名或端口不一样,比如前端用localhost:5500,后端用localhost:3000,浏览器就会拦下来。
解决办法是在后端加跨域配置——比如用ws库的话,创建服务器时加headers配置,把Access-Control-Allow-Origin设为(开发环境用,生产环境要改具体域名),这样浏览器就不会拦截请求了。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别!
站长QQ:709466365 站长邮箱:709466365@qq.com