NodeJS落地WebSocket實(shí)踐前端架構(gòu)師破局技術(shù)
網(wǎng)絡(luò)協(xié)議進(jìn)化
HTTP 協(xié)議是前端最熟悉的網(wǎng)絡(luò)通信協(xié)議。我們通常的打開(kāi)網(wǎng)頁(yè),請(qǐng)求接口,都屬于 HTTP 請(qǐng)求。
HTTP 請(qǐng)求的特點(diǎn)是:請(qǐng)求-> 響應(yīng)??蛻舳税l(fā)起請(qǐng)求,服務(wù)端收到請(qǐng)求后進(jìn)行響應(yīng),一次請(qǐng)求就完成了。也就是說(shuō),HTTP 請(qǐng)求必須由客戶端發(fā)起,服務(wù)端才能被動(dòng)響應(yīng)。
除此之外,發(fā)起 HTTP 請(qǐng)求之前,還需要通過(guò)三次握手建立 TCP 連接。HTTP/1.0 的特點(diǎn)是,每通信一次,都要經(jīng)歷 “三步走” 的過(guò)程 —— TCP 連接 -> HTTP 通信 -> 斷開(kāi) TCP 連接。
這樣的每一次請(qǐng)求都是獨(dú)立的,一次請(qǐng)求完成連接就會(huì)斷開(kāi)。
HTTP1.1 對(duì)請(qǐng)求過(guò)程做了優(yōu)化。TCP 連接建立之后,我們可以進(jìn)行多次 HTTP 通信,等到一個(gè)時(shí)間段無(wú) HTTP 請(qǐng)求發(fā)起 TCP 才會(huì)斷開(kāi)連接,這就是 HTTP/1.1 帶來(lái)的長(zhǎng)連接技術(shù)。
但是即便如此,通信方式依然是客戶端發(fā)起,服務(wù)端響應(yīng),這個(gè)根本邏輯不會(huì)變。
隨著應(yīng)用交互的復(fù)雜,我們發(fā)現(xiàn),有一些場(chǎng)景是必須要實(shí)時(shí)獲取服務(wù)端消息的。
比如即時(shí)聊天,比如消息推送,用戶并不會(huì)主動(dòng)發(fā)起請(qǐng)求,但是當(dāng)服務(wù)器有了新消息,客戶端需要立刻知道并且反饋給用戶。
HTTP 不支持服務(wù)端主動(dòng)推送,但是這些場(chǎng)景又急需解決方案,于是早期出現(xiàn)了輪詢(polling)。輪詢是客戶端定時(shí)向服務(wù)器發(fā)起請(qǐng)求,檢測(cè)服務(wù)端是否有更新,如果有則返回新數(shù)據(jù)。
這種輪詢方式雖然簡(jiǎn)單粗暴,但很顯然有兩個(gè)弊端:
- 請(qǐng)求消耗太大。客戶端不斷請(qǐng)求,浪費(fèi)流量和服務(wù)器資源,給服務(wù)器造成壓力。
- 不能保證及時(shí)??蛻舳诵枰胶饧皶r(shí)性和性能,請(qǐng)求間隔必然不能太小,因此會(huì)有延遲。
隨著 HTML5 推出 WebSocket
,即時(shí)通訊場(chǎng)景終于迎來(lái)了根本解決方案。WebSocket
是全雙工通信協(xié)議,當(dāng)客戶端與服務(wù)端建立連接之后,雙方可以互相發(fā)送數(shù)據(jù),這樣的話就不需要客戶端通過(guò)輪詢這種低效的方式獲取數(shù)據(jù),服務(wù)端有新消息直接推送給客戶端即可。
傳統(tǒng) HTTP 連接方式如下:
## 普通連接 http://localhost:80/test ## 安全連接 https://localhost:80/test
WebSocket 是另一種協(xié)議,連接方式如下:
## 普通連接 ws://localhost:80/test ## 安全連接 wss://localhost:80/test
但是 WebSocket 也不是完全脫離 HTTP 的,若要建立 WebSocket 連接,則必須要客戶端主動(dòng)發(fā)起一個(gè)建立連接的 HTTP 請(qǐng)求,連接成功之后客戶端與服務(wù)端才能進(jìn)行雙向通信。
Socket.IO?
提起用 Node.js 實(shí)現(xiàn) WebSocket,大家一定會(huì)想到一個(gè)庫(kù):Socket.IO
沒(méi)錯(cuò),Socket.IO 是目前 Node.js 在生產(chǎn)環(huán)境中開(kāi)發(fā) WebSocket 應(yīng)用最好的選擇。它功能強(qiáng)大,高性能,低延遲,并且可以一步集成到 express
框架中。
但是也許你不清楚,Socket.IO 并不是一個(gè)純粹的 WebSocket 框架。它是將 Websocket 和輪詢機(jī)制以及其它的實(shí)時(shí)通信方式封裝成了通用的接口,以實(shí)現(xiàn)更高效的雙向通信。
嚴(yán)格來(lái)說(shuō),Websocket 只是 Socket.IO 的一部分。
也許你會(huì)問(wèn):既然 Socket.IO 在 WebSocket 的基礎(chǔ)上做了那么多的優(yōu)化,并且非常成熟,那為什么還要搭一個(gè)原生 WebSocket 服務(wù)?
首先,Socket.IO 不能通過(guò)原生的 ws
協(xié)議連接。比如你在瀏覽器試圖通過(guò) ws://localhost:8080/test-socket
這種方式連接 Socket.IO 服務(wù),是連接不上的。因?yàn)?Socket.IO 的服務(wù)端必須通過(guò) Socket.IO 的客戶端連接,不支持默認(rèn)的 WebSocket 方式連接。
其次,Socket.IO 封裝程度非常高,使用它可能不利于你了解 WebSocket 建立連接的原理。
因此,我們本篇就用 Node.js 中基礎(chǔ)的 ws
模塊,從頭開(kāi)始實(shí)現(xiàn)一個(gè)原生的 WebSocket 服務(wù),并且在前端用 ws 協(xié)議直接連接,體驗(yàn)一把雙向通信的感覺(jué)!
ws 模塊實(shí)現(xiàn)
ws 是 Node.js 下一個(gè)簡(jiǎn)單快速,并且定制程度極高的 WebSocket 實(shí)現(xiàn)方案,同時(shí)包含了服務(wù)端和客戶端。
用 ws
搭建起來(lái)的服務(wù)端,瀏覽器可以通過(guò)原生 WebSocket
構(gòu)造函數(shù)直接連接,非常便捷。ws 客戶端則是模擬瀏覽器的 WebSocket 構(gòu)造函數(shù),用于連接其他 WebSocket 服務(wù)器進(jìn)行通信。
注意一點(diǎn):ws
只能在 Node.js 環(huán)境中使用,瀏覽器中不可用,瀏覽器請(qǐng)直接使用原生 WebSocket 構(gòu)造函數(shù)。
下面開(kāi)始接入,第一步,安裝 ws:
$ npm install ws
安裝好后,我們先搭建一個(gè) ws 服務(wù)端。
服務(wù)端
搭建 websocket 服務(wù)器需要用 WebSocketServer 構(gòu)造函數(shù)。
const { WebSocketServer } = require('ws') const wss = new WebSocketServer({ port: 8080 }) wss.on('connection', (ws, req) => { console.log('客戶端已連接:', req.socket.remoteAddress) ws.on('message', data => { console.log('收到客戶端發(fā)送的消息:', data) }) ws.send('我是服務(wù)端') // 向當(dāng)前客戶端發(fā)送消息 })
把這段代碼寫進(jìn) ws-server.js
然后運(yùn)行:
$ node ws-server.js
客戶端
上一步建好了 WebSocket 服務(wù)器,現(xiàn)在我們?cè)谇岸诉B接并監(jiān)聽(tīng)消息:
var ws = new WebSocket('ws://localhost:8080') ws.onopen = function(mevt) { console.log('客戶端已連接') } ws.onmessage = function(mevt) { console.log('客戶端收到消息: ' + evt.data) ws.close() } ws.onclose = function(mevt) { console.log('連接關(guān)閉') }
將代碼寫入 wsc.html
然后用瀏覽器打開(kāi),看到打印如下:
可以看到,瀏覽器連接成功后,收到服務(wù)端主動(dòng)推送過(guò)來(lái)的消息,然后瀏覽器可以主動(dòng)關(guān)閉連接。
Node.js 環(huán)境下我們看 ws 模塊如何發(fā)起連接:
const WebSocket = require('ws') var ws = new WebSocket('ws://localhost:8080') ws.on('open', () => { console.log('客戶端已連接') }) ws.on('message', data => { console.log('客戶端收到消息: ' + data) ws.close() }) ws.on('close', () => { console.log('連接關(guān)閉') })
代碼與瀏覽器的邏輯一摸一樣,只是寫法稍有些不同,注意區(qū)別。
需要特殊說(shuō)明的一點(diǎn),瀏覽器端監(jiān)聽(tīng) message
事件的回調(diào)函數(shù),參數(shù)是一個(gè) MessageEvent 的實(shí)例對(duì)象,服務(wù)端發(fā)來(lái)的實(shí)際數(shù)據(jù)需要通過(guò) mevt.data
獲取。
而在 ws 客戶端,這個(gè)參數(shù)就是服務(wù)端的實(shí)際數(shù)據(jù),直接獲取即可。
Express 集成
ws 模塊一般不會(huì)單獨(dú)使用,更優(yōu)的方案是集成到現(xiàn)有的框架中。這節(jié)我們將 ws 模塊集成到 Express 框架。
集成到 Express 框架的優(yōu)點(diǎn)是,我們不需要單獨(dú)監(jiān)聽(tīng)一個(gè)端口,使用框架啟動(dòng)的端口即可,并且我們還可以指定訪問(wèn)到某個(gè)路由,才發(fā)起 WebSocket 連接。
幸運(yùn)的是這一切不需要手動(dòng)實(shí)現(xiàn),express-ws 模塊已經(jīng)幫我們做好了大部分的集成工作。
首先安裝,然后在入口文件引入:
var expressWs = require('express-ws')(app)
和 Express 的 Router 一樣,express-ws 也支持注冊(cè)全局路由和局部路由。
先看全局路由,通過(guò) [host]/test-ws
連接:
app.ws('/test-ws', (ws, req) => { ws.on('message', msg => { ws.send(msg) }) })
局部路由則是注冊(cè)在一個(gè)路由組下面的子路由。配置一個(gè)名為 websocket
的路由組并指向 websocket.js
文件,代碼如下:
// websocket.js var router = express.Router() router.ws('/test-ws', (ws, req) => { ws.on('message', msg => { ws.send(msg) }) }) module.exports = router
連接 [host]/websocket/test-ws
就可以訪問(wèn)到這個(gè)子路由。
路由組的作用是定義一個(gè) websocket 連接組,不同需求連接這個(gè)組下的不同子路由。比如可以將 單聊 和 群聊 設(shè)置為兩個(gè)子路由,分別處理各自的連接通信邏輯。
完整代碼如下:
var express = require('express') var app = express() var wsServer = require('express-ws')(app) var webSocket = require('./websocket.js') app.ws('/test-ws', (ws, req) => { ws.on('message', msg => { ws.send(msg) }) }) app.use('/websocket', webSocket) app.listen(3000)
實(shí)際開(kāi)發(fā)中獲取常用信息的小方法:
// 客戶端的IP地址 req.socket.remoteAddress // 連接參數(shù) req.query
WebSocket 實(shí)例
WebSocket 實(shí)例是指客戶端連接對(duì)象,以及服務(wù)端連接的第一個(gè)參數(shù)。
var ws = new WebSocket('ws://localhost:8080') app.ws('/test-ws', (ws, req) => {}
代碼中的 ws
就是 WebSocket 實(shí)例,表示建立的連接。
瀏覽器
瀏覽器的 ws 對(duì)象中包含的信息如下:
{ binaryType: 'blob' bufferedAmount: 0 extensions: '' onclose: null onerror: null onmessage: null onopen: null protocol: '' readyState: 3 url: 'ws://localhost:8080/' }
首先非常關(guān)鍵的是四個(gè)監(jiān)聽(tīng)屬性,用于定義函數(shù):
onopen
:連接建立后的函數(shù)onmessage
:收到服務(wù)端推送消息的函數(shù)onclose
:連接關(guān)閉的函數(shù)onerror
:連接異常的函數(shù)
其中最常用的是 onmessage
屬性,賦值為一個(gè)函數(shù)來(lái)監(jiān)聽(tīng)服務(wù)端消息:
ws.onmessage = mevt => { console.log('消息:', mevt.data) }
還有一個(gè)關(guān)鍵屬性是 readyState
,表示連接狀態(tài),值為一個(gè)數(shù)字。并且每個(gè)值都可以用常量表示,對(duì)應(yīng)關(guān)系和含義如下:
0
: 常量WebSocket.CONNECTING
,表示正在連接1
: 常量WebSocket.OPEN
,表示已連接2
: 常量WebSocket.CLOSING
,表示正在關(guān)閉3
: 常量WebSocket.CLOSED
,表示已關(guān)閉
當(dāng)然最重要的還有 send
方法用于發(fā)送信息,向服務(wù)端發(fā)送數(shù)據(jù):
ws.send('要發(fā)送的信息')
服務(wù)端
服務(wù)端的 ws 對(duì)象表示當(dāng)前發(fā)起連接的一個(gè)客戶端,基本屬性與瀏覽器大致相同。
比如上面客戶端的四個(gè)監(jiān)聽(tīng)屬性,readyState
屬性,以及 send
方法都是一致的。不過(guò)因?yàn)榉?wù)端是 Node.js 實(shí)現(xiàn),因此會(huì)有更豐富的支持。
比如下面兩種監(jiān)聽(tīng)事件的寫法效果是一樣的:
// Node.js 環(huán)境 ws.onmessage = str => { console.log('消息:', str) } ws.on('message', str => { console.log('消息:', mevt.data) })
詳細(xì)的屬性和介紹可以查閱官方文檔
消息廣播
WebSocket 服務(wù)器不會(huì)只有一個(gè)客戶端連接,消息廣播的意思就是把信息發(fā)給所有已連接的客戶端,像一個(gè)大喇叭一樣,所有人都聽(tīng)得到,經(jīng)典場(chǎng)景就是熱點(diǎn)推送。
那么廣播之前,就必須要解決一個(gè)問(wèn)題,如何獲取當(dāng)前已連接(在線)的客戶端?
其實(shí) ws
模塊提供了快捷的獲取方法:
var wss = new WebSocketServer({ port: 8080 }) // 獲取所有已連接客戶端 wss.clients
方便吧。再看 express-ws
怎么獲?。?/p>
var wsServer = expressWebSocket(app) var wss = wsServer.getWss() // 獲取所有已連接客戶端 wss.clients
拿到 wss.clients
后,我們看看它到底是什么樣子。經(jīng)過(guò)打印,發(fā)現(xiàn)它的數(shù)據(jù)結(jié)構(gòu)比想象到還要簡(jiǎn)單,就是由所有在線客戶端的 WebSocket 實(shí)例組成的一個(gè) Set
集合。
那么,獲取當(dāng)前在線客戶端的數(shù)量:
wss.clients.size
簡(jiǎn)單粗暴的實(shí)現(xiàn)廣播:
wss.clients.forEach(client => { if (client.readyState === 1) { client.send('廣播數(shù)據(jù)') } })
這是非常簡(jiǎn)單,基礎(chǔ)的實(shí)現(xiàn)方式。試想一下如果此刻在線客戶有 10000 個(gè),那么這個(gè)循環(huán)多半會(huì)卡死吧。因此才會(huì)有像 socket.io 這樣的庫(kù),對(duì)基礎(chǔ)功能做了大量?jī)?yōu)化和封裝,提高并發(fā)性能。
上面的廣播屬于全局廣播,就是將消息發(fā)給所有人。然而還有另一種場(chǎng)景,比如一個(gè) 5 人的群聊小組聊天,這時(shí)的廣播只是給這 5 人小團(tuán)體發(fā)消息,因此這也叫 局部廣播。
局部廣播的實(shí)現(xiàn)要復(fù)雜一些,一般會(huì)揉合具體的業(yè)務(wù)場(chǎng)景。這就需要我們?cè)诳蛻舳诉B接時(shí),對(duì)客戶端數(shù)據(jù)做持久化處理了。比如用 Redis
存儲(chǔ)在線客戶端的狀態(tài)和數(shù)據(jù),這樣檢索分類更快,效率更高。
局部廣播實(shí)現(xiàn),那一對(duì)一私聊就更容易了。找到兩個(gè)客戶端對(duì)應(yīng)的 WebSocket 實(shí)例互發(fā)消息就行。
安全與認(rèn)證
前面搭建好的 WebSocket 服務(wù)器,默認(rèn)任何客戶端都可以連接,這在生產(chǎn)環(huán)境肯定是不行的。我們要對(duì) WebSocket 服務(wù)器做安全保障,主要是從兩個(gè)方面入手:
- Token 連接認(rèn)證
- wss 支持
下面說(shuō)一說(shuō)我的實(shí)現(xiàn)思路。
Token 連接認(rèn)證
HTTP 請(qǐng)求接口我們一般會(huì)做 JWT 認(rèn)證,在請(qǐng)求頭中帶一個(gè)指定 Header,將一個(gè) token 字符串傳過(guò)去,后端會(huì)拿這個(gè) token 做校驗(yàn),校驗(yàn)失敗則返回 401 錯(cuò)誤阻止請(qǐng)求。
我們上面說(shuō)過(guò),WebSocket
建立連接的第一步是客戶端發(fā)起一個(gè) HTTP 的連接請(qǐng)求,那么我們?cè)谶@個(gè) HTTP 請(qǐng)求上做驗(yàn)證,如果驗(yàn)證失敗,則中段 WebSocket 的連接創(chuàng)建,不就可以了?
順著這個(gè)思路,我們來(lái)改造一下服務(wù)端代碼。
因?yàn)橐?HTTP 層做校驗(yàn),所以用 http
模塊創(chuàng)建服務(wù)器,關(guān)掉 WebSocket 服務(wù)的端口。
var server = http.createServer() var wss = new WebSocketServer({ noServer: true }) server.listen(8080)
當(dāng)客戶端通過(guò) ws://
連接服務(wù)端時(shí),服務(wù)端會(huì)進(jìn)行協(xié)議升級(jí),也就是將 http 協(xié)議升級(jí)成 websocket 協(xié)議,此時(shí)會(huì)觸發(fā) upgrade
事件:
server.on('upgrade', (request, socket) => { // 用 request 獲取參數(shù)做驗(yàn)證 // 1. 驗(yàn)證不通過(guò)判斷 if ('驗(yàn)證失敗') { socket.write('HTTP/1.1 401 Unauthorized\r\n\r\n') socket.destroy() return } // 2. 驗(yàn)證通過(guò),繼續(xù)建立連接 wss.handleUpgrade(request, socket, _, ws => { wss.emit('connection', ws, request) }) }) // 3. 監(jiān)聽(tīng)連接 wss.on('connection', (ws, request) => { console.log('客戶端已連接') ws.send('服務(wù)端信息') })
這樣服務(wù)端認(rèn)證添加完畢,具體的認(rèn)證方法結(jié)合客戶端的傳參方式來(lái)定。
WebSocket 客戶端連接不支持自定義 Header,因此不能用 JWT 的方案,可用方案有兩種:
- Basic Auth
- Quary 傳參
Basic Auth
認(rèn)證簡(jiǎn)單說(shuō)就是賬號(hào)+密碼認(rèn)證,而且賬號(hào)密碼是帶在 URL 里的。
假設(shè)我有賬號(hào)是 ruims,密碼是 123456,那么客戶端連接是這樣:
var ws = new WebSocket('ws://ruims:123456@localhost:8080')
那么服務(wù)端就會(huì)收到這樣一個(gè)請(qǐng)求頭:
wss.on('connection', (ws, req) => { if(req.headers['authorization']) { let auth = req.headers['authorization'] console.log(auth) // 打印的值:Basic cnVpbXM6MTIzNDU2 } }
其中 cnVpbXM6MTIzNDU2 就是 ruims:123456
的 base64 編碼,服務(wù)端可以獲取到這個(gè)編碼來(lái)做認(rèn)證。
Quary
傳參比較簡(jiǎn)單,就是普通的 URL 傳參,可以帶一個(gè)短一點(diǎn)的加密字符串過(guò)去,服務(wù)端獲取到該字符串然后做認(rèn)證:
var ws = new WebSocket('ws://localhost:8080?token=cnVpbXM6MTIzNDU2')
服務(wù)端獲取參數(shù):
wss.on('connection', (ws, req) => { console.log(req.query.token) }
wss 支持
WebSocket 客戶端使用 ws://
協(xié)議連接,那 wss 是什么意思?
其實(shí)非常簡(jiǎn)單,和 https 原理一摸一樣。
https
表示安全的 http 協(xié)議,組成是 HTTP + SSL
wss
則表示安全的 ws 協(xié)議,組成是 WS + SSL
那為什么一定要用 wss 呢?除了安全性,還有一個(gè)關(guān)鍵原因是:如果你的 web 應(yīng)用是 https 協(xié)議,你在當(dāng)前應(yīng)用中使用 WebSocket 就必須是 wss 協(xié)議,否則瀏覽器拒絕連接。
配置 wss 直接在 https 配置中加一個(gè) location
即可,直接上 nginx 配置:
location /websocket { proxy_pass http://127.0.0.1:8080; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; }
然后客戶端連接就變成了這樣:
var ws = new WebSocket('wss://[host]/websocket')
BFF 應(yīng)用
BFF 或許你聽(tīng)說(shuō)過(guò),全稱是 Backend For Frontend
,意思是為前端服務(wù)的后端,在實(shí)際應(yīng)用架構(gòu)中屬于前端和后端的一個(gè) 中間層。
這個(gè)中間層一般是由 Node.js 實(shí)現(xiàn),那么它有什么作用呢?
眾所周知,現(xiàn)在后端的主流架構(gòu)是微服務(wù),微服務(wù)情況下 API 會(huì)劃分的非常細(xì),商品服務(wù)就是商品服務(wù),通知服務(wù)就是通知服務(wù)。當(dāng)你想在商品上架時(shí)給用戶發(fā)一個(gè)通知,可能至少需要調(diào)兩個(gè)接口。
這樣的話對(duì)前端其實(shí)是不友好的,于是后來(lái)出現(xiàn)了 BFF 中間層,相當(dāng)于一個(gè)后端請(qǐng)求的中間代理站,前端可以直接請(qǐng)求 BFF 的接口,然后 BFF 再向后端接口請(qǐng)求,將需要的數(shù)據(jù)組合起來(lái),一次返回前端。
那我們?cè)谏厦嬷v的一大堆 WebSocket 的知識(shí),在 BFF 層如何應(yīng)用呢?
我想到的應(yīng)用場(chǎng)景至少有 4 個(gè):
- 查看當(dāng)前在線人數(shù),在線用戶信息
- 登錄新設(shè)備,其他設(shè)備退出登錄
- 檢測(cè)網(wǎng)絡(luò)連接/斷開(kāi)
- 站內(nèi)消息,小圓點(diǎn)提示
這些功能以前是在后端實(shí)現(xiàn)的,并且會(huì)與其他業(yè)務(wù)功能耦合。現(xiàn)在有了 BFF,那么 WebSocket 完全可以在這一層實(shí)現(xiàn),讓后端可以專注核心數(shù)據(jù)邏輯。
由此可見(jiàn),掌握了 WebSocket 在 Node.js 中的實(shí)踐應(yīng)用,作為前端的我們可以破除內(nèi)卷,在另一個(gè)領(lǐng)域繼續(xù)發(fā)揮價(jià)值,豈不美哉?
源碼地址:https://github.com/ruidoc/blog-codes
以上就是NodeJS落地WebSocket實(shí)踐前端架構(gòu)師破局技術(shù)的詳細(xì)內(nèi)容,更多關(guān)于前端架構(gòu)NodeJS WebSocket的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
使用Nodejs開(kāi)發(fā)微信公眾號(hào)后臺(tái)服務(wù)實(shí)例
這篇文章主要介紹了使用Nodejs開(kāi)發(fā)微信公眾號(hào)后臺(tái)服務(wù)實(shí)例,在這個(gè)實(shí)例中,主要使用到了express, wechat, mongodb, monk等模塊,需要的朋友可以參考下2014-09-09nodejs socket實(shí)現(xiàn)的服務(wù)端和客戶端功能示例
這篇文章主要介紹了nodejs socket實(shí)現(xiàn)的服務(wù)端和客戶端功能,結(jié)合具體實(shí)例形式分析了nodejs基于socket通信實(shí)現(xiàn)的服務(wù)端與客戶端功能相關(guān)操作技巧,需要的朋友可以參考下2017-06-06Node.js中Process.nextTick()和Process.setImmediate()的區(qū)別
這篇文章介紹了Node.js中Process.nextTick()和Process.setImmediate()的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07詳解如何使用node.js的開(kāi)發(fā)框架express創(chuàng)建一個(gè)web應(yīng)用
這篇文章主要介紹了詳解如何使用node.js的開(kāi)發(fā)框架express創(chuàng)建一個(gè)web應(yīng)用,網(wǎng)上各種搜索后,整理了下快速搭建express框架的步驟。非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-12-12使用nodeJS中的fs模塊對(duì)文件及目錄進(jìn)行讀寫,刪除,追加,等操作詳解
nodeJS中fs模塊對(duì)系統(tǒng)文件及目錄進(jìn)行讀寫操作,本文將詳細(xì)介紹nodejs中的文件操作模塊fs的使用方法2020-02-02