本篇文章给大家详细讲解了nodejs+express搭建一个简易的多人聊天室的详细步骤,有兴趣的朋友学习下。
前言
本文主要是笔者在学习node的时候,作为练手的一个小项目,花了几天空余时间,边码边写教程的一个过程。适用于对node理论知识看的多,实战少的同学,那么现在就让我们开始吧!
准备工作
新建一个文件夹 chatroom
在终端输入以下命令,按照步骤npm(没装过的去官网安装下node和npm)会自动给你生成一个package.json文件
安装express和socket.io
package.json文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | {
"name": "chatroom",
"version": "1.0.0",
"description": "A simple chatroom",
"main": "index.js",
"scripts": {
"test": " echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https:
},
"keywords": [
"chatroom",
"nodejs",
"express"
],
"author": "ddvdd",
"license": "ISC",
"bugs": {
"url": "https:
},
"homepage": "https:
}
|
登录后复制
安装express和socket.io
1 2 | npm install express --save
npm install socket.io --save
|
登录后复制
package.json自动新增依赖
1 2 3 4 | "dependencies": {
"express": "^4.16.2",
"socket.io": "^2.0.4"
}
|
登录后复制
因为我们使用express框架写后端服务,用socket.io(Socket.io实际上是WebSocket的父集,Socket.io封装了WebSocket和轮询等方法,他会根据情况选择方法来进行通讯。)来对客户端和服务端建立一个持久链接,便于通讯。
到这里准备工作进行的差不多了,下面我们开始一步步实现。
搭建web服务器
express创建服务
学过node同学应该不陌生,利用http.createServer就能简单的创建一个服务器,这次我们利用express来创建服务。在项目根目录创建一个app.js。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | const express = require ('express');
const app = express();
const fs = require ('fs');
const path = require ('path');
app.listen(3000,()=>{
console.log("server running at 127.0.0.1:3000");
});
app.get('/',(req,res)=>{
res.redirect('/chat.html');
});
app.get('/chat.html',(req,res)=>{
fs.readFile(path.join(__dirname,'./ public /chat.html'), function (err,data){
if (err){
console.error("读取chat.html发生错误",err);
res.send('4 0 4');
} else {
res. end (data);
}
})
});
|
登录后复制
你们看了以后会说,这express框架看来也没那么简便啊,一个最简单的发送单页面的方法跟node自带http.createServer没太大区别饿,也挺麻烦的。从目前来看确实如此,我这不是为了让你们容易理解嘛~ express提供了一个非常强大的中间件,帮我们托管静态资源文件,下面我们就来实现:
1 | app. use ('/',express. static (path.join(__dirname,'./ public ')));
|
登录后复制
代替原来的:
1 2 3 4 5 6 7 8 9 10 | app.get('/chat.html',(req,res)=>{
fs.readFile(path.join(__dirname,'./ public /chat.html'), function (err,data){
if (err){
console.error("读取chat.html发生错误",err);
res.send('4 0 4');
} else {
res. end (data);
}
})
});
|
登录后复制
__dirname表示当前文件所在的绝对路径,所以我们使用path.join将app.js的绝对路径和public加起来就得到了public的绝对路径。用path.join是为了避免出现 ././public 这种奇怪的路径,express.static就帮我们托管了public文件夹中的静态资源。只要有 127.0.0.1:3000/XXX/AAA 的路径都会去public文件夹下找XXX文件夹下的AAA文件然后发送给浏览器。
现在再来看这段代码是不是简介了很多,具体了解app.use()干了什么的同学可以去这里
socket.io建立客户端和服务端的链接
创建完上面的服务后,我们需要把socket.io引用进来,让客户端和服务端建立长久链接。我们把app.js进行如下改造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | const express = require ('express');
const app = express();
const server = require ('http').Server(app);
const io = require ('socket.io')(server);
const path = require ('path');
server.listen(3000,()=>{
console.log("server running at 127.0.0.1:3000");
});
...
...
app. use ('/',express. static (path.join(__dirname,'./ public ')));
io.on('connection',(socket)=>{
});
|
登录后复制
o.on表示监听某个事件,该事件一发生,就触发回调函数。'connection‘就是一个事件名,它已经定义好了,只要用户连接上就会触发。现在app.js基本已经完成,我们在根目录执行:
node app.js
>
现在访问http://127.0.0.1:3000/static/chat.html:

哎?啥也没有。。。那不废话!我们都没url请求对应的静态资源!
添加静态html
我们在项目根目录创建public文件夹,public文件夹里面新建chat.html文件:
1 2 3 4 5 6 7 8 9 10 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天室</title>
</head>
<body>
这是我们的聊天室
</body>
</html>
|
登录后复制
现在我们刷新下页面,你看页面出现了:
>
到这里其实一个最简单的浏览器和web服务器协作的项目就已经完成,后面我们要不断完善页面,给服务器后端加业务功能来实现多人聊天室。
基本功能实现
登陆功能,我们需要一个用户名,(不需要密码),该用户名必须客户端服务器都有存储。每次传输信息基本都需要包括用户名,否则不知道是谁发的。
群聊功能,我们需要分辨信息来己方和对方
登陆功能实现
login页面重构
最基本的登陆界面由一个用户名输入框和登录按钮组成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天室</title>
<style>
*{
margin:0;
padding:0;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
}
.container{
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
background-color: grey;
padding: 50px;
}
.container .title{
width:300px;
margin: 0 auto;
font-size: 30px;
font-family: 'Franklin Gothic Medium';
font-weight: bold;
text-align: center;
margin-bottom:50px;
}
.container .login-wrap{
width:400px;
padding: 20px;
border: 1px solid #000;
margin: 0 auto;
text-align: center;
}
.login-wrap .user-ipt{
width:360px;
text-align: center;
vertical-align: middle;
}
.login-wrap .login-button{
width:60px;
height:24px;
line-height:20px;
font-size: 14px;
padding: 2px 0;
border-radius: 5px;
margin-top:10px;
}
</style>
</head>
<body>
<p class ="container">
<p class ="title">欢迎来到ddvdd聊天室</p>
<p class ="login-wrap">
<p class ="user-ipt">
<span class ="user-name">用户名:</span>
<input id="name" class ="name-ipt" type="text" />
</p>
<button id="loginbutton" class ="login-button">登陆</button>
</p>
</p>
</body>
</html>
|
登录后复制
简单的加点样式,静态页面就完成了,我们刷新下页面:

login页面交互
昨天下午写到一半。。。部门突然要去团建聚会,只能匆匆提交代码,草草了事。今天一大早来到公司继续给大家码
废话不多说进入正题,登陆这块交互,当用户访问服务器并且成功登陆算一个在线登陆人数,每登陆一个用户,服务器都会把用户信息存入一个数组中,保存在服务器,这里要注意一点,服务器会对用户登陆的用户名进行校验,校验结果会返回给客户端,客户端通过校验结果,改变当前页面是否进入聊天页面。
上面的服务器和客户端交互都是通过socket.io来实现通讯的,前端的业务交互我们这里就采用jquery来实现,在public文件夹下新建js文件夹,下载jquery-3.2.1.min.js、新建main.js。然后对chat.html引入需要的sdk:
1 2 3 4 | <script src="js/jquery-3.2.1.min.js"></script>
<script src="js/main.js"></script>
<script src="/socket.io/socket.io.js"></script>
|
登录后复制
引入完sdk,我们对main的js添加登录功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | $( function (){
const url = 'http:
let _username = '';
let _ $inputname = $('#name');
let _ $loginButton = $('#loginbutton');
let socket = io.connect(url);
let setUsername = () => {
_username = _ $inputname .val().trim();
if (_username) {
socket.emit('login',{username: _username});
}
else {
alert('请输入用户名!');
}
};
_ $loginButton .on('click', function (event) {
setUsername();
});
socket.on('loginResult',(data)=>{
if (data.code === 0) {
}
else if (data.code ===1){
alert('用户已登录!');
}
else {
alert('登录失败!');
}
})
});
const express = require ('express');
const app = express();
const server = require ('http').Server(app);
const io = require ('socket.io')(server);
const path = require ('path');
const users = [];
let usersNum = 0;
server.listen(3000,()=>{
console.log("server running at 127.0.0.1:3000");
});
app.get('/',(req,res)=>{
res.redirect('/ static /chat.html');
});
app. use ('/ static ',express. static (path.join(__dirname,'./ public ')));
io.on('connection',(socket)=>{
socket.on('login',(data)=>{
if (checkUserName(data)){
socket.emit('loginResult',{code:1});
}
else {
users.push({
username: data.username,
message: []
});
socket.emit('loginResult',{code:0});
usersNum = users.length;
console.log(`用户${data.username}登录成功,进入ddvdd聊天室,当前在线登录人数:${usersNum}`);
}
});
socket.on('disconnect',()=>{
usersNum = users.length;
console.log(`当前在线登录人数:${usersNum}`);
});
});
const checkUserName = (data) => {
let isExist = false;
users.map((user) => {
if (user.username === data.username){
isExist = true;
}
});
return isExist;
}
|
登录后复制
上面代码大家需要了解以下几点:
socket.on 表示监听事件,后面接一个回调函数用来接收emit发出事件传递过来的对象。
socket.emit 用来触发事件,传递对象给on监听事件。
我们socket连接之后的监听触发事件都要写在io.on('connection')的回调里面,因为这些事件都是连接之后发生的,就算是断开连接的事件 disconnect 也是在连接事件中发生的,没有正在连接的状态,哪来的断开连接呢?
理解虽然服务器端只有app.js一个文件,但是不同的客户端连接后信息是不同的,所以我们必须要将一些公用的信息,比如说,储存所有登录用户的数组,所有用户发送的所有信息存储在外部,一定不能存储在connecion里
效果展示:



群聊功能实现
写完简单的登录功能,现在我们来写这项目最重要的功能群聊。首先我们先来处理下页面,因为功能简单,所以不单独建立html来显示聊天室,就直接写在login页面,通过class名称的变化来切换登录后,聊天室的显示。
聊天室页面重构
下面我们对chat.html进行整改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天室</title>
<script src="js/jquery-3.2.1.min.js"></script>
<script src="js/main.js"></script>
<script src="/socket.io/socket.io.js"></script>
<style>
*{
margin:0;
padding:0;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
}
.container{
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
background-color: darkgrey;
padding: 50px;
overflow-y: scroll;
}
.container .title{
margin: 0 auto;
font-size: 30px;
font-family: 'Franklin Gothic Medium';
font-weight: bold;
text-align: center;
margin-bottom:20px;
}
.container .login-wrap{
width:400px;
padding: 20px;
border: 1px solid #000;
margin: 0 auto;
text-align: center;
}
.login-wrap .user-ipt{
width:360px;
text-align: center;
vertical-align: middle;
}
.login-wrap .login-button{
width:60px;
height:24px;
line-height:20px;
font-size: 14px;
padding: 2px 0;
border-radius: 5px;
margin-top:10px;
}
.chat-wrap .chat-content{
width:100%;
height:600px;
background-color: whitesmoke;
padding:10px;
}
.chat-wrap .send-wrap{
margin-top: 20px;
}
.message-ipt{
width: 200px;
height: 100px;
padding: 0 5px;
vertical-align: bottom;
}
.chat-content p{
display: block;
margin-bottom: 10px;
}
.chat-content p .msg{
display: inline-block;
padding: 8px 11px;
border-radius:6px;
}
.chat-content .self-message .msg{
background-color:#d0e7ff;
border: 1px solid #c9dfff;
}
.chat-content .other-message .msg{
background-color:white;
border: 1px solid #eee;
}
.chat-content .self-message{
text-align:right;
}
.chat-content .other-message{
text-align-last:left;
}
</style>
</head>
<body>
<p class ="container">
<p id="loginbox" class ="login-wrap">
<p class ="title">登录</p>
<p class ="user-ipt">
<span class ="user-name">用户名:</span>
<input id="name" class ="name-ipt" type="text" />
</p>
<button id="loginbutton" class ="login-button">登录</button>
</p>
<p id="chatbox" class ="chat-wrap" style="display:none">
<p id="content" class ="chat-content">
<!-- 聊天内容 -->
</p>
<p class ="send-wrap">
<textarea rows="3" cols="20" id="chatmessage" class ="message-ipt" type="textarea" placeholder="请输入要发送的信息内容"></textarea>
</p>
</p>
</p>
</body>
</html>
|
登录后复制
新增chatbox容器来作为聊天室,里面有一个群聊的聊天框,和一个发送消息的文本框。通过上面loginResult回调,对loginbox进行隐藏,显示chatbox:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | let showChatRoom = () => {
$('#loginbox').hide('slow');
_ $loginButton .off('click');
$(`<p class ="title">欢迎${_username}来到ddvdd聊天室</p>`).insertBefore($("#content"));
$("#chatbox").show('slow');
}
|
登录后复制
消息事件发送监听机制
聊天一定是客户端触发的,所以发送信息是客户端触发,服务器监听。
服务器监听到发送信息的事件后会存储信息,然后触发发送信息成功事件广播给所有客户端,将信息传给所有客
户端。
发送消息sendMessage事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | let sendMessage = function () {
let _message = _ $chattextarea .val();
if (_message) {
socket.emit('sendMessage',{username: _username, message: _message});
}
else {
alert('请输入发送消息!');
}
};
...
_ $chattextarea .on('keyup', function (event) {
if (event.keyCode === 13) {
sendMessage();
_ $chattextarea .val('');
}
});
|
登录后复制
服务器端监听sendMessage事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
socket.on('sendMessage',(data)=>{
for (let _user of users) {
if (_user.username === data.username) {
_user.message.push(data.message);
io.emit('receiveMessage',data);
break ;
}
}
});
|
登录后复制
我们是遍历服务器端的用户数组,找到该用户,将发送的信息存起来,然后触发receiveMessage事件广播到所有浏览器,sendMessage是写在connection里,login之外的,为什么这么做大家一定要理解,发送消息是连接时候做的事情,而不是登录时做的事情。
注意的是,我使用的是io.emit,他是真正的广播到所有浏览器,socket.broadcast.emit则不会广播到自己的浏览器。
客户端监听receiveMessage事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | socket.on('receiveMessage',(data)=>{
showMessage(data);
})
let showMessage = function (data) {
if (data.username === _username){
$("#content").append(`<p class ='self-message'><span class ='msg'>${data.message}</span><span class ='name'> :${data.username}</span></p>`);
} else {
$("#content").append(`<p class ='other-message'><span class ='name'>${data.username}: </span><span class ='msg'>${data.message}</span></p>`);
}
};
|
登录后复制
写到这边,我们的聊天室基本功能已经完成了,来看看效果吧!打开三个浏览器,分别登录老大、老二、老三,发一句“大噶好~,我是渣渣辉!”。



上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
使用Node.js实现压缩和解压缩功能
使用tween.js实现缓动补间动画算法
详细讲解React中的refs(详细教程)
以上是在nodejs+express环境中如何将搭建多人聊天室的详细内容。更多信息请关注PHP中文网其他相关文章!