入门
在本指南中,我们将创建一个基本的聊天应用程序。它几乎不需要任何关于 Node.JS 或 Socket.IO 的基础知识,因此非常适合所有知识水平的用户。
介绍
使用流行的 Web 应用程序堆栈(如 LAMP (PHP))编写聊天应用程序通常非常困难。它涉及轮询服务器以获取更改,跟踪时间戳,并且速度比应有的速度慢得多。
传统上,套接字一直是大多数实时聊天系统构建的解决方案,它在客户端和服务器之间提供双向通信通道。
这意味着服务器可以推送消息到客户端。每当您编写聊天消息时,想法是服务器会获取它并将其推送到所有其他连接的客户端。
Web 框架
第一个目标是设置一个简单的 HTML 网页,它提供一个表单和一个消息列表。为此,我们将使用 Node.JS Web 框架express
。确保Node.JS已安装。
首先,让我们创建一个package.json
清单文件,它描述了我们的项目。我建议您将其放在一个专用的空目录中(我将我的目录命名为chat-example
)。
{
"name": "socket-chat-example",
"version": "0.0.1",
"description": "my first socket.io app",
"dependencies": {}
}
"name" 属性必须是唯一的,您不能使用诸如 "socket.io" 或 "express" 之类的值,因为 npm 在安装依赖项时会报错。
现在,为了轻松地使用我们需要的项目填充dependencies
属性,我们将使用npm install
npm install express@4
安装完成后,我们可以创建一个index.js
文件,它将设置我们的应用程序。
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
app.get('/', (req, res) => {
res.send('<h1>Hello world</h1>');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
这意味着
- Express 初始化
app
为一个函数处理程序,您可以将其提供给 HTTP 服务器(如第 4 行所示)。 - 我们定义了一个路由处理程序
/
,当我们访问网站主页时会调用它。 - 我们让 http 服务器监听端口 3000。
如果您运行node index.js
,您应该看到以下内容

如果您将浏览器指向http://localhost:3000

提供 HTML
到目前为止,在index.js
中,我们调用res.send
并向其传递一个 HTML 字符串。如果我们只是将整个应用程序的 HTML 放置在那里,我们的代码看起来会非常混乱,因此我们将创建一个index.html
文件并提供它。
让我们重构我们的路由处理程序以使用sendFile
。
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
将以下内容放入您的index.html
文件中
<!DOCTYPE html>
<html>
<head>
<title>Socket.IO chat</title>
<style>
body { margin: 0; padding-bottom: 3rem; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }
#form { background: rgba(0, 0, 0, 0.15); padding: 0.25rem; position: fixed; bottom: 0; left: 0; right: 0; display: flex; height: 3rem; box-sizing: border-box; backdrop-filter: blur(10px); }
#input { border: none; padding: 0 1rem; flex-grow: 1; border-radius: 2rem; margin: 0.25rem; }
#input:focus { outline: none; }
#form > button { background: #333; border: none; padding: 0 1rem; margin: 0.25rem; border-radius: 3px; outline: none; color: #fff; }
#messages { list-style-type: none; margin: 0; padding: 0; }
#messages > li { padding: 0.5rem 1rem; }
#messages > li:nth-child(odd) { background: #efefef; }
</style>
</head>
<body>
<ul id="messages"></ul>
<form id="form" action="">
<input id="input" autocomplete="off" /><button>Send</button>
</form>
</body>
</html>
如果您重新启动进程(通过按 Control+C 并再次运行node index.js
)并刷新页面,它应该看起来像这样

集成 Socket.IO
Socket.IO 由两部分组成
- 一个与 Node.JS HTTP 服务器集成的服务器(或安装在 Node.JS HTTP 服务器上)socket.io
- 一个在浏览器端加载的客户端库socket.io-client
在开发过程中,socket.io
会自动为我们提供客户端,正如我们所见,因此现在我们只需要安装一个模块
npm install socket.io
这将安装模块并将依赖项添加到package.json
。现在让我们编辑index.js
以添加它
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
console.log('a user connected');
});
server.listen(3000, () => {
console.log('listening on *:3000');
});
请注意,我通过传递server
(HTTP 服务器)对象来初始化socket.io
的新实例。然后,我监听connection
事件以获取传入的套接字并将其记录到控制台。
现在,在 index.html 中,在</body>
(结束 body 标签)之前添加以下代码段
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
</script>
这就是加载socket.io-client
所需的全部内容,它公开了一个io
全局变量(以及端点GET /socket.io/socket.io.js
),然后连接。
如果您想使用客户端 JS 文件的本地版本,您可以在node_modules/socket.io/client-dist/socket.io.js
中找到它。
您也可以使用 CDN 而不是本地文件(例如<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
)。
请注意,我在调用io()
时没有指定任何 URL,因为它默认尝试连接到提供页面的主机。
如果您现在重新启动进程(通过按 Control+C 并再次运行node index.js
)然后刷新网页,您应该看到控制台打印“用户已连接”。
尝试打开多个选项卡,您将看到多条消息。

每个套接字还会触发一个特殊的disconnect
事件
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
然后,如果您多次刷新选项卡,您就可以看到它在起作用。

发射事件
Socket.IO 的主要思想是您可以发送和接收任何您想要的事件,以及任何您想要的数据。任何可以编码为 JSON 的对象都可以,并且还支持二进制数据。
让我们让用户在输入消息时,服务器将其作为chat message
事件获取。index.html
中的script
部分现在应该如下所示
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
</script>
在index.js
中,我们打印出chat message
事件
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
console.log('message: ' + msg);
});
});
结果应该像以下视频一样
广播
下一个目标是让我们从服务器向其他用户发射事件。
为了向所有人发送事件,Socket.IO 为我们提供了io.emit()
方法。
io.emit('some event', { someProperty: 'some value', otherProperty: 'other value' }); // This will emit the event to all connected sockets
如果您想向除特定发射套接字以外的所有人发送消息,我们可以使用该套接字发射的broadcast
标志
io.on('connection', (socket) => {
socket.broadcast.emit('hi');
});
在这种情况下,为了简单起见,我们将向所有人发送消息,包括发送者。
io.on('connection', (socket) => {
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
});
在客户端,当我们捕获chat message
事件时,我们将将其包含在页面中。全部客户端 JavaScript 代码现在总计为
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var messages = document.getElementById('messages');
var form = document.getElementById('form');
var input = document.getElementById('input');
form.addEventListener('submit', function(e) {
e.preventDefault();
if (input.value) {
socket.emit('chat message', input.value);
input.value = '';
}
});
socket.on('chat message', function(msg) {
var item = document.createElement('li');
item.textContent = msg;
messages.appendChild(item);
window.scrollTo(0, document.body.scrollHeight);
});
</script>
这样就完成了我们的聊天应用程序,大约 20 行代码!它看起来像这样
作业
以下是一些改进应用程序的想法
- 在有人连接或断开连接时向连接的用户广播消息。
- 添加对昵称的支持。
- 不要将相同的消息发送给发送它的用户。相反,在他们按下回车键后立即直接追加消息。
- 添加“{user} 正在输入”功能。
- 显示谁在线。
- 添加私聊功能。
- 分享您的改进!
获取此示例
您可以在 GitHub 上找到它这里。
git clone https://github.com/socketio/chat-example.git