基於Nodejs打造Web架構中間層

前言

Node.js自2009年誕生以來,發展速度至關驚人,目前各類開發框架層出不窮,國內外各大公司都在使用,如國內的阿里的淘寶、天貓、阿里雲、螞蟻金服,騰訊視頻、攜程、百度、網易、蘇寧、京東、愛奇藝、去哪兒、有贊、貝殼找房等等好多企業都在使用,大部分企業把Node.js做爲中間層去應用,今天和你們簡單說說關於基於Nodejs打造Web架構中間層的一些知識。php

1、中間層與中間件

一、什麼是中間層

中間層(Middle Tier)也稱做應用程序服務器層或應用服務層,是用戶接口或 Web 客戶端與數據庫之間的邏輯層。典型狀況下 Web 服務器位於該層,業務對象在此實例化。中間層是生成並操做接收信息的業務規則和函數的集合。它們經過業務規則(能夠頻繁更改)完成該任務,並由此被封裝到在物理上與應用程序程序邏輯自己相獨立的組件中。html

1.1 Node做爲中間層模式

以Node做爲中間層,當客戶端打開一個網站時,先請求到node服務器這一層,經過node服務器轉發請求到後端的服務器,獲取數據,而後返給node的模板引擎,根據視圖模板渲染好模板字符串頁面,再返回給客戶端,直接展現頁面,如圖:前端

18163329db355a3d7e5abdf3.webp.jpg

1.2 負載均衡器-Nginx

Nginx是一個高性能的WEB服務器和反向代理服務器,最經常使用的軟件負載均衡器。node

當訪問量比較大時,頻繁的請求,會給服務帶來很大壓力,經過負載均衡、分流,減輕服務器的壓力;另外一方面,網站部署在多臺服務器,當某臺服務器故障的時候,能夠立刻切換到其它服務器,還能保證網站能正常訪問,這就是負載均衡的優點。jquery

181633291fcbdf31f8f23fe2.webp.jpg

二、什麼是中間件

2.1 中間件概念

中間件(MiddleWare)是一種獨立的系統軟件服務程序,分佈式應用軟件藉助這種軟件在不一樣的技術之間共享資源,中間件位於客戶機服務器的操做系統之上,管理計算資源和網絡通訊。從這個意義上能夠用一個等式來表示中間件:中間件=平臺+通訊,這也就限定了只有用於分佈式系統中才能叫中間件,同時也把它與支撐軟件和實用軟件區分開來。ios

在NodeJS中,中間件主要是指封裝全部Http請求細節處理的方法。一次Http請求一般包含不少工做,如記錄日誌、ip過濾、查詢字符串、請求體解析、Cookie處理、權限驗證、參數驗證、異常處理等,但對於Web應用而言,並不但願接觸到這麼多細節性的處理,所以引入中間件來簡化和隔離這些基礎設施與業務邏輯之間的細節,讓開發者可以關注在業務的開發上,以達到提高開發效率的目的。中間件能夠理解爲一個對用戶請求進行過濾和預處理的東西,它通常不會直接對客戶端進行相應,而是將處理以後的結果傳遞下去。簡單來講就是實現某種功能的函數。web

Express是一個自身功能極簡,徹底是路由和中間件構成一個web開發框架:從本質上來講,一個Express應用就是在調用各類中間件,中間件機制如圖所示:
中間件.pngajax

2.2 中間件機制核心實現

中間件是從Http請求發起到響應結束過程當中的處理方法,一般須要對請求和響應進行處理,所以一個基本的中間件的形式以下:redis

`const middleware = (req, res, next) => {
// TODO
next()
}`算法

2、中間層的意義

Node.js是一個Javascript運行環境。Node.js 使用事件驅動, 非阻塞I/O 模型而得以輕量和高效,很是適合在分佈式設備上運行數據密集型的實時應用。Node.js是單進程、單線程運行機制,經過事件輪詢(event loop)來實現併發操做,並且性能很好。

Node.js最大的改良架構就是"增長了中間層",先後端分離,使用Node.js來作‘BBF(backend of frontend)’在傳統後端加入了Node.js這一層,經過此有兩點好處,前端接管了view層,後端渲染也開始所有由前端掌控,另外一個就是接口層增長了一層。在先後端分離的自然選擇下,Node.js中間層能夠承擔更多的責任。

一、Node.js中間層可作的工做

  • 代理:在開發環境下,咱們能夠利用代理來,解決最多見的跨域問題;在線上環境下,咱們能夠利用代理,轉發請求到多個服務端。
  • 緩存:緩存實際上是更靠近前端的需求,用戶的動做觸發數據的更新,Node.js中間層能夠直接處理一部分緩存需求。
  • 限流:Node.js中間層,能夠針對接口或者路由作響應的限流。
  • 日誌:相比其餘服務端語言,Node.js中間層的日誌記錄,能更方便快捷的定位問題(是在瀏覽器端仍是服務端)。
  • 監控:擅長高併發的請求處理,作監控也是合適的選項。
  • 鑑權:有一箇中間層去鑑權,也是一種單一職責的實現。
  • 路由:前端更須要掌握頁面路由的權限和邏輯。
  • 服務端渲染:Node.js中間層的解決方案更靈活,好比SSR、模板直出、利用一些JS庫作預渲染等等。

二、Node.js中間層帶來的好處

  • 經過PC Web本身的中間層,能夠按照業務定製化接口,擴大前端展示的能力和範圍;
  • 中間層接口由使用接口的前端工程師開發,對展示和接口的功能更加熟悉,避免了之前的工做模式中接口方跟各方的需求對接、溝通、聯調時間,這樣使得項目的推動更加順利,項目迭代會更快;
  • 中間層使用NodeJS,開發語言是JavaScript,跟如今前端工程師的工做語言同樣,減小了學習成本;
  • 中間層接口的開發由前端工程師同時負責開發,既節省了人力成本,同時又提升了前端開發人員的技術能力,使得前端工程師向全棧工程師邁進。

三、Node.js中間層的優點

  • 功能分離,減輕板塊負擔;
  • 跨系統、跨終端都可重用頁面數據校驗、邏輯代碼,無需由於新系統、終端的接入而重寫校驗;
  • 只在中間件中作一次數據校驗,避免了前端作數據校驗的同時後端也要作校驗的重複,在有效保證數據的有效性的同時下降了團隊總體的工做量;
  • 處理數據邏輯,解放了前端既要作頁面渲染又要寫複雜的邏輯,使得頁面開發人員專一於頁面渲染,不只使得分工更爲明確,項目協做效率更高,更重要的是快速響應頁面使得頁面加載更快,用戶體驗更好,避免了瀏覽器長時間顯示空白頁面的不友好體驗,真正的先後端分離。

3、中間層的實現

前面寫了不少理論方面的知識,接下來本身手動來簡單實現Node.js基於Koa框架實現的中間層。

一、後端提供的接口

先了解一下後端提供的一個接口,根據前端頁面輸入不一樣帳號信息,後端接口會返回不一樣的值,如圖:

php.png
這段PHP代碼是根據前端傳給不一樣的用戶名和密碼狀態返回不一樣的狀態碼。

二、搭建前端頁面

前端頁面用了ejs模板引擎採用服務端渲染方式來進行。前端頁面主要有三個代碼的文件,app.js,admin.js,admin.ejs。

2.1 項目代碼結構

WX202003240944192x.png

2.2 項目代碼展現

一、是app.js代碼

`const Koa = require('koa');
// 路由
const Router = require('koa-router');
// 模板引擎
const ejs = require('koa-ejs');
// 數據解析
const body = require('koa-bodyparser');
// 處理靜態文件
const static = require("koa-static");
const path = require('path');
const app = new Koa();
ejs(app,{

root:path.resolve(__dirname,"template"), 
layout:false,
viewExt:"ejs",
cache:false,
debug:false

})
const router = new Router();
app.use(body());
router.get("/",ctx => {

ctx.body = '主頁';

})
router.use("/admin",require("./router/admin"));
app.use(static('./static'));
app.use(router.routes());
app.listen(3000);`

二、登陸頁面文件,用ejs模板引擎來處理

`<!DOCTYPE html>
<html lang="en">
<head>

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>我是管理頁面</title>
<script src="/js/jquery.min.js"></script>

</head>
<body>

<p>用戶:<input type="text"></p>
<p>密碼:<input type="password"></p>
<button>提交</button>
<script>
   $(function(){
       $('button').click(function(){
           var username = $(':text').val();
           var password = $(':password').val();
           $.ajax({
               url:'/admin/login',
               method:'post',   
               data:{
                   username,
                   password
               },
               success(data){
                   console.log(data);
               }
           })
       })
   })
</script>

</body>
</html>`

三、代碼逐步實現邏輯

一、使用上面的登陸頁代碼,而後admin.js頁面代碼以下

`const Router = require('koa-router');
const querystring = require('querystring');
const router = new Router();
router.get('/',async ctx=>{

await ctx.render('admin/admin')

})
router.post("/login",async ctx => {

const { username,password } = ctx.request.body;
console.log(username,password);

})
module.exports = router.routes();`

此時登陸頁面輸入用戶名和密碼點擊提交時會輸出結構以下代碼:

``^CedzdeMacBook-Pro-5:0323 edz$ nodemon app.js
[nodemon] 2.0.2
[nodemon] to restart at any time, enter rs
[nodemon] watching dir(s): .
[nodemon] watching extensions: js,mjs,json
[nodemon] starting node app.js
admin 123456 //後端拿到了前端傳給的數據``

此時傳過的數據後端會拿他與數據庫做比對,進行處理,而Node.js只充當中介做用,不作數據的處理。

二、咱們接着看,把要的數據傳個服務端,使用axios發送數據到服務端,其中裏面用到了數據格式的轉換:

`const Router = require('koa-router');
const querystring = require('querystring');
const router = new Router();
router.get('/',async ctx=>{

await ctx.render('admin/admin')

})
//此處爲中間層,起到中介做用,會把數據發給後端接口
router.post("/login",async ctx => {

const { username,password } = ctx.request.body;
//console.log(username,password);
//要數據傳給服務端,使用axios發送數據到服務端
const {data} = await axios({
    url:'http://localhost/login/check.php', 
    method:'post',
    data:{
        username,
        password
    },
    // username=admin&password=123456查詢字符串
    //數據格式轉換,前端是個JSON數據格式,後端拿到的是表單數據
    transformRequest:[
        data =>{
            return querystring.stringify(data)
        }
    ]
})

})
module.exports = router.routes();`

此時登陸頁面輸入用戶名和不一樣的密碼和空密碼時點擊提交時會輸出結構以下代碼:

``^CedzdeMacBook-Pro-5:0323 edz$ nodemon app.js
[nodemon] 2.0.2
[nodemon] to restart at any time, enter rs
[nodemon] watching dir(s): .
[nodemon] watching extensions: js,mjs,json
[nodemon] starting node app.js
{ code:1 }
{ code:0 }
{ code:3 }``

三、這時咱們把後端傳回的接口數據在進行從新包裝一下,添加以下代碼:

`// 從新包裝

if(data.code !== 1){
    // return中斷條件
    return ctx.body = {
        code:401,
        message:'未經受權'
    }
}
// 前端本身定義的提示語 ,後端專一邏輯開發,不用在和前端定義接口
ctx.body = {
   code:200,
   message:'校驗成功'
}`

這時頁面會返回通過前端包裝的提示語,如圖所示:

結果.png

總的處理路由的admin.js代碼文件以下:

`const Router = require('koa-router');
const axios = require('axios');
const querystring = require('querystring');
const router = new Router();
router.get('/',async ctx=>{

await ctx.render('admin/admin')

})
//此處爲中間層,起到中介做用,會把數據發給後端接口
router.post("/login",async ctx => {

const { username,password } = ctx.request.body;
//console.log(username,password);
//要數據傳給服務端,使用axios發送數據到服務端
const {data} = await axios({
    url:'http://localhost/login/check.php', //後端提供的一個接口文件
    method:'post',
    data:{
        username,
        password
    },
    // username=admin&password=123456查詢字符串
    //數據格式轉換,前端是個JSON數據格式,後端拿到的是表單數據
    transformRequest:[
        data =>{
            return querystring.stringify(data)
        }
    ]
})
// 從新包裝
// console.log(data);
if(data.code !== 1){
    // return中斷條件
    return ctx.body = {
        code:401,
        message:'未經受權'
    }
}
// 前端本身定義的提示語 ,後端專一邏輯開發,不用在和前端定義接口
ctx.body = {
   code:200,
   message:'校驗成功'
}

})
module.exports = router.routes();`

服務端不要暴露太多給用戶信息,不用提示用戶名正確或者密碼錯誤,防止被別人猜,前端根據後端提供的狀態碼從新定義輸出提示內容,對用戶來講特別的友好,不論後端給前端什麼樣的接口內容,前端均可以包裝接口,因此後端只要返回給前端數據就能夠了,接口的定義前端本身能夠進行包裝。

4、總結

中間層已經爲愈來愈多的大公司所應用,進入中間層後,前端能作的事情愈來愈多,將觸角伸向了服務器,除了先後端分離外,還能作redis緩存,負載均衡策略。另外一方面,不止是Node.js能作中間層,PHP也能夠,由於Node.js是用js寫的,Node.js的生態很成熟,對於前端人員來講,比較容易上手。

Web端的開發團隊是需求鏈中的最上游、數據鏈的下游,不少產品功能都受限於業務接口,中間層提供了一種可能,讓咱們Web前端開發工做有了本身的接口開發能力能夠對接最原始數據,既減小了前端開發中的侷限性,也讓前端團隊在開發過程當中有了更多的想象力,能更好的根據業務須要快速開展項目。
招聘信息

好將來技術團隊正在熱招前端、算法、流媒體後臺開發等各個方向高級開發工程師崗位,你們可掃描下方二維碼或微信搜索關注「好將來技術」,點擊本公衆號「技術招聘」欄目瞭解詳情,歡迎感興趣的夥伴加入咱們!

也許你還想看

DStack--基於flutter的混合開發框架

WebRTC源碼分析——視頻流水線創建(上)

"考試"背後的科學:教育測量中的理論與模型(IRT篇)

相關文章
相關標籤/搜索