使用NodeJS、Socket.io和ExpressJS进行实时聊天

redmaomail 2024-07-24 21:52 阅读数 66 #wordpress

红帽云邮外贸主机

使用nodejs、socket.io和expressjs进行实时聊天

NodeJS 使我能够用我最喜欢的语言之一编写后端代码:JavaScript。它是构建实时应用程序的完美技术。在本教程中,我将向您展示如何使用 ExpressJS 和 Socket.io 构建网络聊天应用程序。


设置环境

当然,首先要做的就是在您的系统上安装 NodeJS。如果您是 Windows 或 Mac 用户,可以访问 nodejs.org 并下载安装程序。如果您更喜欢 Linux,我建议您参考此链接。虽然我不会详细介绍这一点,但如果您遇到任何安装问题,我很乐意提供帮助;只需在本文下方发表评论即可。

安装 NodeJS 后,您就可以设置所需的工具了。

  1. ExpressJS - 这将管理服务器和对用户的响应
  2. Jade - 模板引擎
  3. Socket.io - 允许前端和后端之间的实时通信

继续,在空目录中创建一个包含以下内容的 package.json 文件。

{
    "name": "RealTimeWebChat",
    "version": "0.0.0",
    "description": "Real time web chat",
    "dependencies": {
        "socket.io": "latest",
        "express": "latest",
        "jade": "latest"
    },
    "author": "developer"
}
登录后复制

通过使用控制台(在 Windows - 命令提示符下),导航到您的文件夹并执行:

npm install
登录后复制

几秒钟之内,您就会将所有必需的依赖项下载到 node_modules 目录中。


开发后端

让我们从一个简单的服务器开始,它将提供应用程序的 HTML 页面,然后继续更有趣的部分:实时通信。使用以下核心expressjs代码创建一个index.js文件:

var express = require("express");
var app = express();
var port = 3700;

app.get("/", function(req, res){
    res.send("It works!");
});

app.listen(port);
console.log("Listening on port " + port);
登录后复制

上面,我们创建了一个应用程序并定义了它的端口。接下来,我们注册了一个路由,在本例中,它是一个不带任何参数的简单 GET 请求。目前,路由的处理程序只是向客户端发送一些文本。最后,当然,在底部,我们运行服务器。要初始化应用程序,请从控制台执行:

node index.js
登录后复制

服务器正在运行,因此您应该能够打开http://127.0.0.1:3700/并看到:

It works!
登录后复制

现在,我们应该提供 HTML,而不是“它有效”。使用模板引擎代替纯 HTML 可能会更有益。 Jade 是一个很好的选择,它与 ExpressJS 有很好的集成。这是我在自己的项目中通常使用的。创建一个名为 tpl 的目录,并将以下 page.jade 文件放入其中:

!!!
html
    head
        title= "Real time web chat"
    body
        #content(style='width: 500px; height: 300px; margin: 0 0 20px 0; border: solid 1px #999; overflow-y: scroll;')
        .controls
            input.field(style='width:350px;')
            input.send(type='button', value='send')
登录后复制

Jade 的语法并不复杂,但是,要获得完整的指南,我建议您参考jade-lang.com。为了将 Jade 与 ExpressJS 一起使用,我们需要进行以下设置。

app.set('views', __dirname + '/tpl');
app.set('view engine', "jade");
app.engine('jade', require('jade').__express);
app.get("/", function(req, res){
    res.render("page");
});
登录后复制

此代码通知 Express 您的模板文件所在位置以及要使用的模板引擎。它全部指定将处理模板代码的函数。一旦一切设置完毕,我们就可以使用 response 对象的 .render 方法,并将我们的 Jade 代码发送给用户。

此时的输出并不特殊;无非是一个 div 元素(id 为 content 的元素),它将用作聊天消息的容器和两个控件(输入字段和按钮),我们将使用它们来发送消息。

因为我们将使用一个外部 JavaScript 文件来保存前端逻辑,所以我们需要通知 ExpressJS 在哪里寻找此类资源。创建一个空目录 public,并在调用 .listen 方法之前添加以下行。

app.use(express.static(__dirname + '/public'));
登录后复制

到目前为止一切顺利;我们有一个成功响应 GET 请求的服务器。现在,是时候添加 Socket.io 集成了。更改此行:

app.listen(port);
登录后复制

至:

var io = require('socket.io').listen(app.listen(port));
登录后复制

上面,我们将 ExpressJS 服务器传递给了 Socket.io。实际上,我们的实时通信仍然会发生在同一端口上。

接下来,我们需要编写从客户端接收消息并将其发送给所有其他客户端的代码。每个 Socket.io 应用程序都以 connection 处理程序开始。我们应该有一个:

io.sockets.on('connection', function (socket) {
    socket.emit('message', { message: 'welcome to the chat' });
    socket.on('send', function (data) {
        io.sockets.emit('message', data);
    });
});
登录后复制

传递给处理程序的对象 socket 实际上是客户端的套接字。将其视为服务器和用户浏览器之间的连接点。连接成功后,我们发送 welcome 类型的消息,当然,还会绑定另一个将用作接收器的处理程序。结果,客户端应该发出一条名为 send 的消息,我们将捕获该消息。接下来,我们只需使用 io.sockets.emit 将用户发送的数据转发到所有其他套接字。

通过上面的代码,我们的后端已准备好向客户端接收和发送消息。让我们添加一些前端代码。


开发前端

创建 chat.js,并将其放置在应用程序的 public 目录中。粘贴以下代码:

window.onload = function() {

    var messages = [];
    var socket = io.connect('http://localhost:3700');
    var field = document.getElementById("field");
    var sendButton = document.getElementById("send");
    var content = document.getElementById("content");

    socket.on('message', function (data) {
        if(data.message) {
            messages.push(data.message);
            var html = '';
            for(var i=0; i<messages.length; i++) {
                html += messages[i] + '<br />';
            }
            content.innerHTML = html;
        } else {
            console.log("There is a problem:", data);
        }
    });

    sendButton.onclick = function() {
        var text = field.value;
        socket.emit('send', { message: text });
    };

}
登录后复制

我们的逻辑包装在 .onload 处理程序中,只是为了确保所有标记和外部 JavaScript 均已完全加载。在接下来的几行中,我们创建一个数组,它将存储所有消息、一个 socket 对象以及一些 DOM 元素的快捷方式。同样,与后端类似,我们绑定一个函数,它将对套接字的活动做出反应。在我们的例子中,这是一个名为 message 的事件。当此类事件发生时,我们期望收到一个对象,data,其属性为 message。将该消息添加到我们的存储中并更新 content div。我们还包含了发送消息的逻辑。这非常简单,只需发出一条名为 send 的消息。

如果你打开http://localhost:3700,你会遇到一些错误弹出窗口。这是因为我们需要更新 page.jade 以包含必要的 JavaScript 文件。

head
    title= "Real time web chat"
    script(src='/chat.js')
    script(src='/socket.io/socket.io.js')
登录后复制

请注意,Socket.io 管理 socket.io.js 的交付。您不必担心手动下载此文件。

我们可以在控制台中使用 node index.js 再次运行我们的服务器并打开http://localhost:3700。您应该会看到欢迎消息。当然,如果你发送一些东西,应该显示在内容的div中。如果您想确保它有效,请打开一个新选项卡(或者更好的是,一个新浏览器)并加载应用程序。 Socket.io 的伟大之处在于,即使您停止 NodeJS 服务器它也能工作。前端将继续工作。一旦服务器再次启动,您的聊天也会正常。

在目前的状态下,我们的聊天并不完美,需要一些改进。


改进

我们需要做的第一个更改是消息的标识。目前,尚不清楚哪些消息是由谁发送的。好处是我们不必更新 NodeJS 代码来实现这一点。这是因为服务器只是转发 data 对象。因此,我们需要在那里添加一个新属性,并稍后读取它。在对 chat.js 进行更正之前,让我们添加一个新的 input 字段,用户可以在其中添加他/她的姓名。在 page.jade 中,更改 controls div:

.controls
    | Name: 
    input#name(style='width:350px;')
    br
    input#field(style='width:350px;')
    input#send(type='button', value='send')
登录后复制

接下来,在code.js中:

window.onload = function() {

    var messages = [];
    var socket = io.connect('http://localhost:3700');
    var field = document.getElementById("field");
    var sendButton = document.getElementById("send");
    var content = document.getElementById("content");
    var name = document.getElementById("name");

    socket.on('message', function (data) {
        if(data.message) {
            messages.push(data);
            var html = '';
            for(var i=0; i<messages.length; i++) {
                html += '<b>' + (messages[i].username ? messages[i].username : 'Server') + ': </b>';
                html += messages[i].message + '<br />';
            }
            content.innerHTML = html;
        } else {
            console.log("There is a problem:", data);
        }
    });

    sendButton.onclick = function() {
        if(name.value == "") {
            alert("Please type your name!");
        } else {
            var text = field.value;
            socket.emit('send', { message: text, username: name.value });
        }
    };

}
登录后复制

为了总结这些变化,我们:

  1. 为用户名的 input 字段添加了新快捷方式
  2. 稍微更新了消息的呈现方式
  3. 向对象添加了一个新的 username 属性,该属性将发送到服务器

如果消息数量过多,用户将需要滚动 div:

content.innerHTML = html;
content.scrollTop = content.scrollHeight;
登录后复制

请记住,上述解决方案可能不适用于 IE7 及更低版本,但没关系:IE7 是时候消失了。但是,如果您想确保支持,请随意使用 jQuery:

$("#content").scrollTop($("#content")[0].scrollHeight);
登录后复制

如果发送消息后输入字段被清除,那就太好了:

socket.emit('send', { message: text, username: name.value });
field.value = "";
登录后复制

最后一个无聊的问题是每次点击发送按钮。通过一点 jQuery,我们可以监听用户何时按下 Enter 键。

$(document).ready(function() {
    $("#field").keyup(function(e) {
        if(e.keyCode == 13) {
            sendMessage();
        }
    });
});
登录后复制

可以注册函数 sendMessage,如下所示:

sendButton.onclick = sendMessage = function() {
    ...
};
登录后复制

请注意,这不是最佳实践,因为它注册为全局函数。但是,对于我们在这里的小测试来说,一切都很好。


结论

NodeJS 是一项非常有用的技术,它为我们提供了巨大的力量和乐趣,特别是考虑到我们可以编写纯 JavaScript 的事实。正如您所看到的,仅用几行代码,我们就编写了一个功能齐全的实时聊天应用程序。非常整洁!

想要了解有关使用 ExpressJS 构建 Web 应用程序的更多信息?我们为您服务!

使用NodeJS、Socket.io和ExpressJS进行实时聊天的详细内容,更多请关注红帽云邮其它相关文章!


红帽云邮外贸主机

分享到:
版权声明:本站内容源自互联网,如有内容侵犯了你的权益,请联系删除相关内容。
    红帽云邮外贸主机
热门
    红帽云邮外贸主机
    红帽云邮外贸主机