NodeJS 使我能夠用我最喜歡的語言之一編寫后端代碼:JavaScript。它是構建實時應用程序的完美技術。在本教程中,我將向您展示如何使用 expressJS 和 Socket.io 構建網絡聊天應用程序。
設置環境
當然,首先要做的就是在您的系統上安裝 nodejs。如果您是 windows 或 Mac 用戶,可以訪問 nodejs.org 并下載安裝程序。如果您更喜歡 linux,我建議您參考此鏈接。雖然我不會詳細介紹這一點,但如果您遇到任何安裝問題,我很樂意提供幫助;只需在本文下方發表評論即可。
安裝 NodeJS 后,您就可以設置所需的工具了。
- ExpressJS – 這將管理服務器和對用戶的響應
- Jade – 模板引擎
- 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 的元素),它將用作聊天消息的容器和兩個控件(輸入字段和按鈕),我們將使用它們來發送消息。 p>
因為我們將使用一個外部 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></messages.length>'; } 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>' + (messages[i].username ? messages[i].username : 'Server') + ': '; 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 }); } }; } </messages.length>
為了總結這些變化,我們:
- 為用戶名的 input 字段添加了新快捷方式
- 稍微更新了消息的呈現方式
- 向對象添加了一個新的 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 應用程序的更多信息?我們為您服務!