❝自從Node.js出現以後,相應的web框架就出現了,並且都是比較容易上手和搭建的,框架中都有一個很重要的概念「中間件」,今天就來扒一下其中的奧妙。html
❞
還記得以前面試的時候,我說用過Node搭建了一個小型的後臺框架,而後面試官就問了一下你用過什麼經常使用的中間件嗎?前端
我當時知道中間件就是一個相似插件同樣,依次執行的東西。雖然我在項目當中也用到了相似body-parser、express.static()這些,奈何年少無知我不知道這就是中間件。如今想一想要是再問我中間件原理就更不懂了。vue
如今的中間件是挺多的,能夠知足咱們不少的數據處理與請求,咱們今天就來看一下中間件這個神奇的東西到底神在哪?node
得益於JavaScript的發展,使得Node誕生了,可以在服務器端運行JS代碼
,這無疑是使人激動的事情,Express其實就是一個Node.js Web程序框架
,簡單來講就是快速構建一個「後臺」。咱們用很簡單的代碼就能夠搭建一個服務器,不用費勁心思來使用其餘的語言來搭建,並且其餘語言在什麼也沒幹的狀況下就出現極多的代碼。git
Node與其餘傳統的Web服務器的重大區別就是它是單線程
的,它能夠簡化Web程序的編寫,若是要實現多線程就啓動多個Node實例便可。並且Node是跨平臺的,與平臺是無關的
,咱們能夠在Windows或者Linux操做系統上均可運行。web
咱們在使用Express編寫應用程序的時候通常都會有固定的代碼,有必定的目錄結構。這中「常規」的代碼就是咱們所說的腳手架,讓咱們更方便地開發。咱們隨便建一個文件夾來使用Express。面試
npm init
使用這一行命令來初始化一個package.json文件
,可是要注意的是package.json的name不能叫express,否則會在下一句命令會報錯。express
npm install express --save
安裝express,成功以後你會在項目的根目錄看到多了node_modules文件夾,這裏就是第三方的應用包,咱們的express也會安裝在這裏。npm
由於這個文件夾極大,甚至包含了成百上千的包,因此代碼提交的時候咱們確定不會帶上它的。因此咱們在根目錄下面就建立一個.gitignore文件
,內容就是node_modules
,用與忽略這個文件夾。json
新建入口文件 app.js
在根目錄新建一個入口文件,一般叫app.js或者index.js均可以。
var express = require("express");
var app = express();
app.set("port", process.env.PORT || 3000);
// 定製 404 頁面
app.use(function (req, res) {
res.type("text/plain");
res.status(404);
res.send("404 - Not Found");
});
// 定製 500 頁面
app.use(function (err, req, res, next) {
console.error(err.stack);
res.type("text/plain");
res.status(500);
res.send("500 - Server Error");
});
app.listen(app.get("port"), function () {
console.log(
"Express started on http://localhost:" +
app.get("port") +
"; press Ctrl-C to terminate."
);
});
複製代碼
那其實這樣你就建立了小型的服務器了,接下來就直接啓動一下,node app.js就會發現它已是監聽了3000端口。可是咱們發現他是沒有東西的,由於咱們沒有配置路由,默認就是返回錯誤頁404。
咱們嘗試配置一個的路由,主要要在404路由以前,否則也會出現404。
上面咱們看到了404和500使用的是app.use而不是路由的形式,這是一種中間件的寫法,咱們能夠理解爲沒有路由匹配的時候走的方向。
app.get("/", function (req, res) {
res.type("text/plain");
res.send("這是首頁");
});
app.get("/about", function (req, res) {
res.type("text/plain");
res.send("這是關於頁");
});
複製代碼
咱們開發中不免會有一些圖片等資源的引入,express給咱們提供了一種便於資源引入的方法,咱們直接在app.js文件的路由開始以前就加入這一行代碼:
var express = require("express");
var app = express();
app.use(express.static(__dirname + '/public'));//須要加入的代碼
複製代碼
意思就是這裏的資源能夠不經任何處理就直接發送給客戶端,能夠放置圖片、CSS文件等。
咱們能夠加載靜態資源文件,可是咱們要使用html模板進行內容的渲染就要加入模板引擎了,可是這種模板引擎的我用的比較少,我通常都會結合vue進行渲染的。可是今天咱們就來探討一下不用vue要怎麼渲染出來。
首先咱們要安裝一下模板殷勤express-handlebars:
npm install express-handlebars
複製代碼
咱們如今跟目錄之下創建一個views文件夾,而後再創建一個index.html文件用於渲染。
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{title}}</title>
</head>
<body>
<h1>首頁</h1>
<img src="/express.png" alt="" style="width: 200px;height: 100px;">
{{#each list}}
<h2>暱稱:{{this.name}}</h2>
<h2>年齡:{{this.age}}</h2>
<hr>
{{/each}}
</body>
</html>
複製代碼
app.js
var express = require("express");
var app = express();
const exphbs = require("express-handlebars");//引入模板
app.engine(//設置模板
"html",
exphbs({
layoutsDir: "views",
defaultLayout: "layout",
extname: ".html",
})
);
複製代碼
而後咱們修改一下以前的請求根路徑的路由,修改爲:
app.get("/", function (req, res) {
res.render("index", {
layout: false,
title: "首頁",
list: [
{
name: "張三",
age: 20,
},
{
name: "李四",
age: 15,
},
],
});
});
複製代碼
以上改好以後重啓運行,打開localhost:3000
你就能夠看到你的頁面渲染出來了。若是你的網站是比較小型的,通常使用這樣的輕量級框架就能夠完成了,可是模板語法本身也要了解一下。
其實中間件很好理解,想象一下有一個長的管道,中間能夠加入不少東西,這些東西就是咱們所說的中間件。
express的中間件能夠分紅幾種:
「應用級中間件」
咱們使用的app.use('/',(req,res)={})
這種就是,直接掛載到app下面的。
app.use((req,res,next) => {
//這個中間件是全部都執行的,沒有掛載到具體的路徑
next(); // 控制權下一個中間件
})
app.get("/about", function (req, res) {
res.type("text/plain");
res.send("這是關於頁");
});
複製代碼
「路由級中間件」
路由級中間件和上面應用級中間件相似,可是它綁定對象不是app而是爲express.Router()對象。
router.get('/getValue', (req, res, next) => {
api.getValue(req, res, next);
});
router.post('/setValue', (req, res, next) => {
api.setValue(req, res, next);
});
複製代碼
「錯誤處理中間件」
錯誤處理中間件有四個參數,定義錯誤處理中間件必須使用這四個參數。即便不須要next對象,也必須在參數中聲明它,否者中間件會識別爲一個常規中間件,不能處理錯誤。
// 定製 500 頁面
app.use(function (err, req, res, next) {
console.error(err.stack);
res.type("text/plain");
res.status(500);
res.send("500 - Server Error");
});
複製代碼
「內置中間件」
express.static是 Express 惟一內置的中間件。它基於 serve-static,負責在 Express 應用中提託管靜態資源。
var options = {
dotfiles: 'ignore',
etag: false,
extensions: ['htm', 'html'],
index: false,
maxAge: '1d',
redirect: false,
setHeaders: function (res, path, stat) {
res.set('x-timestamp', Date.now());
}
}
app.use(express.static('public', options));
複製代碼
「第三方中間件」
這個其實有不少,咱們使用的body-parser這種就是屬於第三方的中間件。這裏經常使用的有:
其實咱們不少的功能均可以經過第三方的中間件來完成,前端真的不簡單,有不少大佬在爲了前段的發展全力以赴,我只會CV。
好了,說了這麼多,咱們就來分析一些這個中間件是怎麼實現的,如何纔可使得管道平穩運行。咱們能夠發現中間件都是有執行順序的,先後的執行結果是不同的。有點相似咱們隊列的樣子。
接下來就參照這種思想來實現一下這中間件的核心代碼。
var http = require('http');
function express() {
var funcs = []; // 待執行的函數數組
var app = function (req, res) {
var i = 0;
function next() {
var task = funcs[i++]; // 取出函數數組裏的下一個函數
if (!task) { // 若是函數不存在,return
return;
}
task(req, res, next); // 不然,執行下一個函數
}
next();
}
app.use = function (task) {
funcs.push(task);
}
return app; // 返回實例
}
複製代碼
這裏就是核心代碼了,精髓都在這裏,接下來咱們就寫一些本身的中間件,來測試一下是否可行。
var app = express();
function middlewareA(req, res, next) {
console.log('中間件1開始...');
next();
console.log('中間件1結束...');
}
function middlewareB(req, res, next) {
console.log('中間件2開始...');
next();
console.log('中間件2結束...');
}
function middlewareC(req, res, next) {
console.log('中間件3開始...');
next();
console.log('中間件3結束...');
}
app.use(middlewareA);
app.use(middlewareB);
app.use(middlewareC);
http.createServer(app).listen('3000', function () {
console.log('listening 3000....');
});
複製代碼
運行這一段js代碼的時候,控制檯就出現了中間件的執行過程。它有一種相似於先進後出的「棧結構」。
以上就是本文的全部內容了,主要介紹了Web框架Express的使用方法,以及使用模板引擎進行數據渲染的具體操做。咱們還重點了解了Express的中間件實現原理與過程,瞭解其中的思想。你們也能夠去了解一下常見的中間件,試着去使用它們,你會發現開發竟是如此簡單。
咱們也知道除了Express框架以外還有Koa框架,它也是由Express的原班人員打造出來的,我認爲只要是用的舒服就好,沒有必要說哪一個好哪一個很差。
參考文章: