Socket.io 显示访客数量
如何
安装
npm i
跑步
npm start dev
在以下地址打开资源管理器:localhost:3000
嘿👋,希望你一切都好,
我们已经好久没见面了!
今天我想和大家聊聊socket.io
这个非常好的小库允许我们轻松地在 nodejs 下管理我们的套接字。
事实上,最近几天我不得不使用它来在我的个人网站上实时显示当前访问者的计数器。
这非常简单,所以我们看看它进展如何!
让我们按章节来组织一下这一切:
因此,如果您允许的话,让我们从头开始,创建这个项目!
我们仍然有一些期望,从某种意义上说,我们不会“仅仅”从文档中复制/粘贴代码。
我们将使用以下内容制作一个小型服务器:
来吧,让我们终于开始了!
这部分非常简单,我们将快速浏览第一个命令。
mkdir socketio-numberOfOnlineUser-ts
cd socketio-numberOfOnlineUser-ts
npm init -y
(使用 -y 是因为我们不想在 cli 上浪费时间,-y 默认批准所有)
npm i express rxjs socket.io
npm i -D @types/express @types/socket.io nodemon ts-node tslint typescript
"scripts": {
"dev": "nodemon",
"start": "ts-node src/index.ts",
}
在你的 package.json 下方创建一个nodemon.json文件,内容如下:
touch nodemon.json
并将其放在上面(它将使用此配置作为 nodemon 命令,即你的npm run dev):
{
"ignore": ["**/*.test.ts", "**/*.spec.ts", "node_modules"],
"watch": ["src"],
"exec": "npm start",
"ext": "ts"
}
npx tsc --init --rootDir src --outDir dist --module commonjs --lib es2015 --sourceMap true --target es6 --esModuleInterop true
mkdir src src/models src/services
touch src/index.ts src/index.html src/models/index.ts src/models/Socket.ts src/services/index.ts src/services/Socket.ts
通常,在这个阶段,你的层次结构应该是这样的⬇️对于项目的创建阶段,我们很好!下一步!
终于有代码了!好玩的部分来了!
因此,让我们打开 vscode 并从index.ts文件开始。
对于这一部分,我们将在 express 下初始化一个基本的节点服务器,你知道,这里没有秘密,所以它看起来像这样:
import express from "express"; // We import express as listener, you know.
import * as http from "http"; // We import http for init the server
// Anyway, if we don't do it, express does it secretly
const app = express(); // Init express
const server = http.createServer(app); // Init server avec use express as listener
const port = 3000;
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html"); // We Will use the index.html file to see our work
});
server.listen(port, () => {
return console.log(`server is listening on ${port}`); // No need to comment that, no?
});
在这个阶段,我们只有一个 nodejs 服务器正在运行并返回一个空白页面。
我们继续吧。
让我们准备我们的index.html文件,我们只是想实时查看在线用户的数量。
让我们把这个放在上面:
<div>
<p>Number of users : <span id="numberOfUsers"></span></p>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io("localhost:3000");
var numberOfUsers = document.getElementById("numberOfUsers");
socket.on("numberOfUser", function (data) {
numberOfUsers.textContent = data;
});
</script>
啊,终于第一次引用 SocketIo 了,但是发生了什么?
这里我们在客户端初始化一个 SocketIo 实例(使用 io('backend adress')),该实例将尝试连接到地址 localhost:3000 上“正常”可用的套接字,一旦连接,该实例将等待服务器发出“numberOfUser”事件(使用 socket.on('') 方法)。
但是,您的服务器还没有关于此主题的任何内容,因此如果您测试该页面,只会收到错误消息。
但让我们继续。
我们继续创建数据模型,因为是的,我们将从套接字发送数据,但为了防止应用程序将来的复杂性,我们将保持干净并快速创建数据模型。
进入src/models文件夹并将其放入我们的文件Socket.ts
export interface NumberOfUser {
data?: number;
}
哦,但是在我们的 Socket.ts 文件旁边,我们有一个 index.ts 文件,让我们来处理它,以防它是一个“桶”,有助于有效地组织我们将来的所有导入/导出。
因此,使用它并将其放入其中:
export * from "./Socket";
好的,我们的模型没问题,现在我们知道通过我们的套接字传递的数据是什么样的。
现在让我们来处理一下 Socket 实例!终于!
因此,让我们来处理src/services文件夹,里面有我们的小桶index.ts(现在你知道该如何处理它了吧?导出 blablabla)
让我们继续讨论最重要的文件src/services/Socket.ts
我们最终将使用 RxJS 创建一个“可观察”的变量。
也就是说,每当该变量中包含的数据发生变化时,就会执行一个函数(回调)。
因此我们可以让我们的套接字轻松且动态地做出反应!
我们还将有一个函数来增加或减少numberOfUser 的值,以便客户端可以在访问者登录/注销时看到变化。
简而言之,这就是我们著名文件的状态⬇️
import * as socketio from "socket.io";
import * as http from "http"; // Just for typing, we like typing !
import { BehaviorSubject } from "rxjs";
import { NumberOfUser } from "../models/Socket"; // Here our model, cause we like typing things !
export class SocketService {
private numberOfUser: BehaviorSubject<NumberOFUser> =
new BehaviorSubject<NumberOFUser>({
data: 0,
}); // Here our "stream pipe" of the NumberOfUser Data.
private numberOfUser$: Observable<NumberOFUser> =
this.numberOfUser.asObservable(); // Here's our "Observable" data.
private io!: socketio.Server; // Our Socket instance
constructor(server: http.Server) {
this.io = new socketio.Server(server, { cors: { origin: "*" } }); // We init our Socket instance with the server as parameter
}
public listenStore() {
this.numberOfUser$.subscribe((store) => {
// subscribe is called at each store value change !
this.io.emit("numberOfUser", store.data); // So at each value change, we emit this value to the client with the event name "numberOfUser"
});
}
public listenUserActivity() {
this.io.on("connection", (client) => {
// When a user do a connection at our socket, the "connection" event is called. It's a default event from socket.io.
this.numberOfUser.next({
data: this.numberOfUser.value.data + 1, // we get the actual value of our "Observable" and
}); // we change the data with the function "next"
client.once("disconnect", () => {
// When a user do a disconnection, the "disconnect" event is called. It's a default event from socket.io.
this.numberOfUser.next({
data: this.numberOfUser.value.data - 1,
}); // You know what next do now.
});
});
}
}
这就是 socket.ts 文件!
现在我们已经有一个具有我们想要的逻辑的现成的 Socket 服务,我们需要让我们的服务器知道它的存在。
为此,我们将像这样编辑 src/index.ts 文件
import express from "express";
import * as http from "http";
import { SocketService } from "./services"; // We import our SocketService, Thanks to the index.ts file, we don't need to specify where exactly the Socket.ts file is located.
const app = express();
const server = http.createServer(app);
const port = 3000;
const socketService = new SocketService(server); // We instantiate our SocketService
app.get("/", (req, res) => {
res.sendFile(__dirname + "/index.html");
});
socketService.listenStore(); // We ask to our service to listen the change of the "Observable" data and emit the change to our socket by the "numberOfUser" event.
socketService.listenUserActivity(); // We listen the activity of the socket and change the state of the "Observable" data when a desired event is triggered ("connection" or "disconnect")
server.listen(port, () => {
return console.log(`server is listening on ${port}`);
});
因此,如果我们回到客户端,我们就可以看到我们所有的工作!
当我们加载页面时,我们会看到numberOfUser值发生变化,当我们离开页面时也是如此。
这是工作!
因此您可以从那里开始使您的逻辑更加复杂!
但你到底在说什么?你的客户端不在 Node 端?你用的是 Vuejs/Angular 或 Next 之类的前端框架。
没问题,只需在前端使用socket.io-client包并执行以下操作⬇️:
import { io, Socket } from "socket.io-client";
import { Observable, BehaviorSubject } from "rxjs";
export interface SocketData {
numberOfUser?: number;
}
export class SocketService {
private socket!: Socket;
private store: BehaviorSubject<SocketData> = new BehaviorSubject<SocketData>({
numberOfUser: 0,
});
private store$: Observable<SocketData> = this.store.asObservable();
constructor() {
this.socket = io("YOUR_BACKEND_URL");
this.socket.on("numberOfUser", (data) => {
this.emit(data); // At each "numberOfUser" event we modify our "Observable" data.
});
}
public emit(store: SocketData): void {
this.store.next(store);
}
public listen(): Observable<SocketData> {
return this.store$; // You will be able to use this.socketService.listen().subscribe(), it's the same logic as we see above !
}
}
我想我们已经看完了主要部分,所以我们可以在这里停下来!
在下一篇文章中,我们将看到如何在 apache2 下在您自己的 VPS 下部署它,您会发现它很简单!
如果你有什么想法,我都听着!比如,我不太愿意让用户互相发送表情符号。
编辑于 2022 年 11 月 14 日:将内容设置得更通用一些/或者更简单地添加其他“Observables”值
鏂囩珷鏉ユ簮锛�https://dev.to/noprod/socketio-show-number-of-visitor-337