您好,登錄后才能下訂單哦!
本篇內容介紹了“Nodejs中間層的原理是什么”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
nodejs的出現為前端行業帶來了無限的可能性,讓很多原來只負責客戶端開發的同學也慢慢開始接觸和使用服務器端技術.
雖然nodejs帶來了很多的好處,但是它也存在自身的局限性.和那些傳統老牌的編程語言相比,如JAVA,PHP.nodejs并不能成為它們的替代品,而且在可預估的未來,也很難撼動那些老牌編程語言的地位.
目前nodejs主要有以下幾個應用場景.
前端工程化,比如rollup,webpack在工程化方向的探索
nodejs中間層
客戶端集成nodejs,比如electron
市面上一些不太復雜的應用選擇nodejs作為后端編程語言
本文主要講一講nodejs作為中間層的一些實踐,查看下圖.
傳統的的開發模式由瀏覽器直接和Server層直接通信,中間層的加入意味著在瀏覽器和Server層之間額外添加了一層.
原來客戶端直接向Server發送請求,Server層收到請求后經過計算處理將結果返回給瀏覽器.
如今瀏覽器將請求發送給node層,node層經過一輪處理后再向Server層發起請求.Server層處理完畢將響應結果返回給node層,node層最后將數據返回給瀏覽器.
因為node層的出現,Server層可以只用關注業務本身,而不必理會前端對字段的特殊要求。
node層可以向server層獲取數據,再通過對數據的計算整合轉換成符合前端UI要求的數據格式.另外整個應用如果采用微服務架構,那么Server層會有很多臺管理單獨業務模塊的服務器,node層就很好的適配了微服務的架構,它可以向多臺服務器發起請求獲取到不同模塊的數據再整合轉化發送給前端.
下面著重介紹一下nodejs作為中間層的部分實踐.
代理轉發在實際中有很多廣泛的應用.瀏覽器首先將請求發送給node服務器,請求收到后node服務器可以對請求做一些處理,比如將原來的路徑變換一下,請求頭的信息改變一下,再把修改后的請求發送給遠程真實的服務器.
遠程服務器計算出響應結果再返回給node服務器,node服務器仍然可以對響應做選擇性處理再分返回給瀏覽器.
代理轉發可以解決前端日常開發中經常遇到的跨域問題,另外它還屏蔽了遠程真實服務器的細節,讓瀏覽器只與node服務器通信.下面是簡單的實踐.
const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express();//創建應用 app.use("/api",createProxyMiddleware( //設置代理轉發 { target: 'http://www.xxx.com', //舉例隨便寫的地址 changeOrigin: true, pathRewrite: function (path) { return path.replace('/api', '/server/api'); } }) ); app.use("*",(req,res)=>{ //不是以'/api'開頭的路由全部返回"hello world" res.send("hello world"); }) app.listen(3000);
http-proxy-middleware是一個第三方依賴包,可以非常方便設置代理轉發,需要通過npm安裝.
如果當前訪問的路徑是以/api開頭,那么該請求就會被http-proxy-middleware攔截.觀察http-proxy-middleware里面配置的參數.
target代表遠程真實服務器的地址.
changeOrigin設置為true,表示將請求轉發到target地址上.
pathRewrite是對請求路徑做一下處理,將/api轉換成/server/api.
上面的案例意思很明顯,假如當前瀏覽器訪問http://localhost:3000/api/list.因為這個路徑以/api開頭所以會被攔截,從而觸發pathRewrite函數修改訪問路徑.最終訪問路徑就變成了http://www.xxx.com/server/api/list,然后就會向這個路徑發起請求,得到響應后再返回給瀏覽器.
上面介紹的接口轉發在實踐中很少會單獨應用,如果僅僅只是為了轉發一下數據,那還不如直接用nginx配置一下,轉發就搞定了.
如果接口聚合和接口轉發都需要,那么從代碼層面去解決還是優先考慮的方式.
接口聚合是什么意思呢?假設現在企業有兩個銷售體系,一個是線上的電商平臺銷售,另一個是線下實體店.它們分別屬于不同的團隊運營,維護著不同的數據系統.
如果當前請求只是想查詢一下電商平臺某款商品的信息,只需要將接口轉發給電商平臺系統即可.同理如果僅僅只是查詢線下實體店某一天的銷售業績,可以直接把請求轉發給線下數據系統查詢,再把響應數據返回.上面介紹的插件http-proxy-middleware支持配置多個代理路徑,詳細可查詢文檔.
現在有這么一個需求,目標是查詢本周某款商品在線上和線下銷售數據的對比.那么這個時候就需要node層向兩個遠程服務器發送請求分別獲取線上銷售數據和線下銷售數據,將這兩部分數據聚合處理后再返回給前端.簡單實踐如下.
const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express();//創建應用 //偽代碼 app.get("/getSaleInfo",async (req,res)=>{ const online_data = await getOnline(); //獲取線上數據 const offline_data = await getOffline(); //獲取線下數據 res.send(dataHanlder(online_data,offline_data)); //對數據處理后返回給前端 }) proxyHanlder(app);//偽代碼,將代理轉發的邏輯封裝起來 app.use("*",(req,res)=>{ res.send("hello world"); }) app.listen(3000);
/getSaleInfo代表著將兩條數據聚合的自定義路由,如果需要聚合數據的需求比較多,這塊邏輯要單獨封裝到路由模塊中管理,并且要寫在代理轉發的前面.
這樣就確保了需要轉發的接口就交給轉發的邏輯處理,需要個性化處理數據的接口就單獨編寫路由操作數據.
緩存對于提升系統性能,減小數據庫壓力起到了無足輕重的作用.一般常用的緩存軟件是redis,它可以被理解成數據存儲在內存當中的數據庫.由于數據放在內存中,讀寫速度非常快,能極快的響應用戶的請求.
在node層部署redis管理緩存數據,可以提升整體應用性能.但不是什么數據都建議存放在redis中,只有那些不經常變動的數據應該設置成緩存.
比如商品的信息數據,瀏覽器對某個商品發起請求,想查看該商品的詳情.請求第一次到達node層,redis此時是空的.那么node開始請求server層得到響應結果,此時在將響應結果返回給瀏覽器之前,將該次請求的訪問路徑作為key值,響應結果作為value存儲到redis中.這樣之后再有相同的請求發來時,先查看redis有沒有緩存該請求的數據,如果緩存了直接將數據返回,如果沒有緩存再去請求server層,把上述流程再走一遍.
redis還可以對緩存數據設置過期時間和清除,可以根據具體的業務操作.簡單實踐如下.
const express = require('express'); const app = express();//創建應用 //偽代碼 app.use("*",(req,res,next)=>{ const path = req.originalUrl; //獲取訪問路徑 if(redisClient.getItem(path)){ //查看redis中有沒有緩存該條接口的數據 res.send(redisClient.getItem(path)); // 返回緩存數據 }else{ next(); //不執行任何操作,直接放行 } }) aggregate(app); //偽代碼,將接口聚合的邏輯封裝起來 proxyHanlder(app);//偽代碼,將代理轉發的邏輯封裝起來 app.use("*",(req,res)=>{ res.send("hello world"); }) app.listen(3000);
node做中間層可以對前端無節制的訪問做限制.比如有些惡意的腳本循環訪問接口,一秒鐘訪問幾十次增大了服務器的負載.
redis可以幫助我們實現這一功能.用戶第一次訪問,解析出本次請求的ip地址,將ip作為key值,value置為0存到redis中.
用戶第二次訪問,取出ip找到redis中對應的value,然后自增1.如果是相同的人重復大量訪問,value在短期內就自增到了很大的數字,我們可以每次獲取這個數字判端是否超過了設定的預期標準,超過則拒絕本次請求.簡單實踐如下.
const express = require('express'); const app = express();//創建應用 //偽代碼 app.use("*",(req,res,next)=>{ const ip = req.ip; let num = 0; if(redisClient.getItem(ip)){ //是否緩存了當前的ip字段 num = redisClient.incr(ip); //每訪問一下,計數加1 }else{ redisClient.setItem(ip,0); redisClient.setExpireTime(5); //設置過期時間為5秒,5秒后再獲取該ip為空 } if(num > 20){ res.send("非法訪問"); }else{ next();//放行 } }) cacheData(app)//偽代碼.緩存接口數據 aggregate(app); //偽代碼,將接口聚合的邏輯封裝起來 proxyHanlder(app);//偽代碼,將代理轉發的邏輯封裝起來 app.use("*",(req,res)=>{ res.send("hello world"); }) app.listen(3000);
在應用的前面設置一層限流中間件,每次訪問來臨先判端是否緩存過.第一次訪問肯定沒有緩存,就將當前ip對應的值設置為0并添加過期時間為5秒鐘.下一次相同的用戶再訪問時就會將value自增1.
最后的效果就達到了5秒內調用接口的次數超過20次便拒絕訪問.
系統沒有日志,相當于人沒有雙眼.日志可以幫助我們發現分析定位線上系統出現的錯誤.另外通過日志數據也可以進行統計計算得出某些結論和趨勢.
node層能夠承擔起管理日志的功能,以接口訪問日志為例.在系統中新建一個日志文件夾,每次有請求訪問時,首先解析請求的路徑、當前的訪問時間以及攜帶的參數和終端數據信息.然后在日志文件夾創建一個txt文件存放當天日志情況,將上述數據和該請求的響應結果組合成一條記錄插入txt文件中.下一次訪問繼續走上面流程往txt文件添加訪問日志.像上面介紹的代理轉發,插件http-proxy-middleware支持配置如何返回響應結果,那么在相應的事件函數鉤子里就可以同時得到請求和響應,有了這兩塊數據就可以存放到日志中.
這里還能制定很多的配置策略.可以選擇一天一個日志文本,如果訪問量巨大也可以選擇一個小時一個日志文本,依據實際情況而定.
另外隨著時間的延長,日志文件夾的文件內容會越來越多.這就需要編寫linux操作系統定時任務來遷移和備份這些日志數據.
日志操作簡單實踐如下.
//偽代碼 app.use("/getList",async (req,res)=>{ const list = await getProductList(); //獲取商品數據 const { 訪問時間,訪問路徑,參數 } = req; logger.log('info',`${訪問時間}-${訪問路徑和參數}:${list}`);//將數據存儲到日志文件中 res.send(list);//將結果返回給客戶端 })
中間層另外還可以做很多其他事情,比如監控、鑒權和服務器端渲染(SSR).這部分由于內容比較多可以單獨成章,網絡上也有大量如何實踐的文章,可搜索查閱學習.
其實上面所談到的所有功能其他編程語言都可以做到,這也成為了很多人質疑是否需要在架構上額外再加一層的顧慮.
添加nodejs中間層,對于前端同學來說肯定是好消息.因為它能讓前端承擔更多的工作任務,讓前端的業務比重變大.另外后端從此只需要關注自身業務,前端繼續干著自己擅長的事,從整體上是能提升開發效率.
但從宏觀角度上看,架構額外增加一層勢必會造成整個應用性能上的損耗,另外在部署,測試層面都會增大運維成本.
當下前后端分離已經成為了主流的開發模式,很多類型的應用需要seo的支持以及首屏加載速度,因此服務器端渲染不可或缺.前端項目目前大多采用react或vue框架開發,如果用nodejs承擔服務器端渲染的任務,那么可以確保一套代碼既可以做客戶端渲染也能支持服務器端渲染,而這些工作都可以讓前端程序員獨立來完成.服務器端渲染技術非常重要,后面會開一個小節單獨講解.
綜上來看,nodejs做中間層最有價值的功能是服務器端渲染和接口數據聚合.如果企業應用數量較少業務簡單還沒有規模化,不建議添加中間層,那樣反而讓簡單的事情變得復雜.
“Nodejs中間層的原理是什么”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。