Express 框架簡介


1、Express 框架簡介及初體驗

1.1、Express 框架是什么

Express 是一個屬於 Node 平台的 Web 應用開發框架,它提供了一系列的強大特性,幫助你創建各種 Web 應用

我們可以使用 npm install express 命令進行下載安裝。

1.2、Express 框架特性

●提供了方便簡潔的路由定義方式

●對獲取 HTTP 請求參數進行了簡化處理

●對模板引擎支持程序高,方便渲染動態 HTML 頁面

●提供了中間件機制,有效控制 HTTP 請求

●擁有大量第三方中間件對功能進行擴展

1.3、原生 Node.js 與 Express 框架對比之路由 

原始 node.js 代碼:

app.on('request', (req, res) => {
  // 獲取客戶端的請求路徑
  let { pathname } = url.parse(req.url);
  // 對請求路徑進行判斷 不同的路徑地址響應不同的內容
  if (pathname == '/' || pathname == '/index') {
    res.end('歡迎來到首頁');
  } else if (pathname == '/list') {
    res.end('歡迎來到列表頁');
  } else if (pathname == '/about') {
    res.end('歡迎來到關於我們頁');
  } else {
    res.end('抱歉,您訪問的頁面出錯了');
  }
});

express 框架代碼:

// 當客戶端以 get 方式訪問 / 時
app.get('/', (req, res) => {
  // 對客戶端做出響應
  res.send('Hello Express');
});
// 當客戶端以 post 方式訪問 /add 路由時
app.get('/add', (req, res) => {
  // 對客戶端做出響應
  res.send('使用 post 方式請求了 /add 路由');
});

例子:

新建 framework 項目文件夾,並切換到命令行工具,輸入:npm install express 下載安裝框架。

新建 01.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

app.get('/', (req, res) => {
  // send() 向客戶端響應
  // 1、send() 內部會檢測響應內容的類型
  // 2、send() 會自動設置 http 狀態碼
  // 3、send() 會幫我們自動設置響應的內容類型及編碼
  res.send('hello express');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

切換到命令行工具,輸入:

node 01.js

打開瀏覽器,輸入:http://localhost:3000/ 可以看到:

在增加一個 /list:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

app.get('/', (req, res) => {
  // 1、send() 內部會檢測響應內容的類型
  // 2、send() 會自動設置 http 狀態碼
  // 3、send() 會幫我們自動設置響應的內容類型及編碼
  res.send('hello express');
})

app.get('/list', (req, res) => {
  res.send({name: '張三', age: 20});
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

重新運行:node 01.js

刷新頁面可以看到:

2、中間件

2.1、什么是中間件

中間件就是一堆方法,可以接收客戶端發來的請求,可以對請求做出響應,也可以將請求繼續交給下一個中間件繼續處理。

中間件方法由 Express 提供,負責攔截請求,請求處理函數由開發人員提供,負責處理請求。

app.get('請求路徑', '處理函數') // 接收並處理get請求
app.post('請求路徑', '處理函數') // 接收並處理post請求

可以針對同一個請求設置多個中間件,對同一個請求進行多次處理。

app.get('/request', (req, res, next) => {
  req.name = '張三';
next() }) app.get(
'/request', (req, res) => { res.send(req.name); })

可以調用 next 方法將請求的控制權交給下一個中間件,直到遇到結束請求的中間件。

例子:新建 02.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

app.get('/request', (req, res, next) => {
  req.name = '張三';
  next();
});

app.get('/request', (req, res) => {
  res.send(req.name);
});

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 02.js

回到瀏覽器輸入:http://localhost:3000/request ,可以看到:

2.2、app.use 中間件用法 

app.use 匹配所有的請求方式,可以直接傳入請求處理函數,代表接收所有的請求。

app.use((req, res, next) => {
  console.log(req.url);
  next();
});

app.use 第一個參數也可以傳入請求地址,代表不論什么請求方式,只要是這個請求地址就接收這個秦秋。

app.use('/admn', (req, res, next) => {
  console.log(req.url);
  next();
});

例子:新建 03.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

// 接收所有請求的中間件
app.use((req, res, next) => {
  console.log('請求走了 app.use 中間件')
  next()
})
// 當客戶端訪問 /request 請求的時候,才走當前的中間件
app.use('/request', (req, res, next) => {
  console.log('請求走了 app.use /request 中間件')
  next()
})

app.get('/list', (req, res) => {
  res.send('/list');
})

app.get('/request', (req, res, next) => {
  req.name = '張三';
  next();
});

app.get('/request', (req, res) => {
  res.send(req.name);
});

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具輸入:nodemon 03.js

在瀏覽器中輸入:http://localhost:3000/request

在瀏覽器中輸入:http://localhost:3000/list

2.3、中間件應用

1、路由保護,客戶端在訪問需要登錄的頁面時,可以先使用中間件判斷用戶登錄狀態,用戶如果未登錄,則攔截請求,直接響應,禁止用戶進入需要登錄的頁面。

例子:新建 04.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

app.use('/admin', (req, res, next) => {
  // 用戶沒有登錄
  let isLogin = false;
  // 如果用戶登錄
  if (isLogin) {
    // 讓請求繼續向下執行
    next()
  } else {
    // 如果用戶沒有登錄,直接第客戶端做出響應
    res.send('您還沒有登錄,不能訪問當前頁面');
  }
})

app.get('/admin', (req, res) => {
  res.send('您已經登錄,可以訪問當前頁面');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸人:nodemon 04.js

在瀏覽器中輸入:http://localhost:3000/admin ,可以看到:

把 isLogin 改為: let isLogin = true;,在重新刷新頁面,可以看到:

2、網站維護公告,在所有路由的最上面定義接收所有請求的中間件,直接為客戶端做出響應,網站正在維護中。

例子:繼續編輯 04.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

// 網站維護公告
app.use((req, res, next) => {
  res.send('當前網站正在維護中...');
})

app.use('/admin', (req, res, next) => {
  // 用戶沒有登錄
  let isLogin = true;
  // 如果用戶登錄
  if (isLogin) {
    // 讓請求繼續向下執行
    next()
  } else {
    // 如果用戶沒有登錄,直接第客戶端做出響應
    res.send('您還沒有登錄,不能訪問當前頁面');
  }
})

app.get('/admin', (req, res) => {
  res.send('您已經登錄,可以訪問當前頁面');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

回到瀏覽器中,隨便輸入那個請求地址,頁面都顯示:

3、自定義 404 頁面

中間是有順序的,如果從上到下都沒有匹配成功,那么就說明用戶訪問的這個請求路徑是不存在的。

例子:繼續編輯 04.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

// 網站維護公告
// app.use((req, res, next) => {
//   res.send('當前網站正在維護中...');
// })

app.use('/admin', (req, res, next) => {
  // 用戶沒有登錄
  let isLogin = true;
  // 如果用戶登錄
  if (isLogin) {
    // 讓請求繼續向下執行
    next()
  } else {
    // 如果用戶沒有登錄,直接第客戶端做出響應
    res.send('您還沒有登錄,不能訪問當前頁面');
  }
})

app.get('/admin', (req, res) => {
  res.send('您已經登錄,可以訪問當前頁面');
})

app.use((req, res, next) => {
  res.send('當前訪問的頁面不存在');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在瀏覽器中輸入:http://localhost:3000/add 可以看到:

不過在 network 里看到的狀態碼是 304

要想顯示為 404 的話,需要修改代碼:

app.use((req, res, next) => {
  // 為客戶端響應 404 狀態碼以及提示信息
  // res.status(404)
  res.status(404).send('當前訪問的頁面不存在');
})

刷新頁面后可以看到:

2.4、錯誤處理中間件

在程序執行的過程中,不可避免的會出現一些無法預料的錯誤。比如文件讀取失敗,數據庫連接失敗等。

錯誤處理中間件是一個集中處理錯誤的地方。

代碼示例:

app.use((err, req, res, next) => {
  res.status(500).send('服務器發生未知錯誤');
})

例子:新建 05.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

app.get('/index', (req, res) => {
  throw new Error('程序發生了未知錯誤')
})

// 錯誤處理中間件
app.use((err, req, res, next) => {
  res.status(500).send(err.message);
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 05.js

在瀏覽器中輸入:http://localhost:3000/index ,可以看到:

注意:錯誤處理中間件只能捕捉到同步代碼執行出錯。如果異步代碼執行出錯,需要手動去觸發這個錯誤中間件。

當程序出現錯誤時,調用 next() 方法,並且將錯誤信息通過參數的形式傳遞給 next() 方法,即可觸發錯誤處理中間件。

示例代碼:

app.get('/', (req, res, next) => {
  fs.readFile('./file-dose-exist', (err, data) => {
    if (err) {
      next(err);
    }
  })
})

例子:修改 05.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();
const fs = require('fs');

app.get('/index', (req, res, next) => {
  // throw new Error('程序發生了未知錯誤')
  // res.send('程序正常執行')
  fs.readFile('./demo.txt', 'utf8' ,(err, result) => {
    if (err != null) {
      next(err)
    } else {
      res.end(result)
    }
  })
})

// 錯誤處理中間件
app.use((err, req, res, next) => {
  res.status(500).send(err.message);
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在瀏覽器中刷新頁面,可以看到:沒有找到文件

如果修改為當前目錄下有的文件:

fs.readFile('./01.js', 'utf8' ,(err, result) => {

刷新瀏覽器,可以看到:

2.5、捕獲錯誤

在 node.js 中,異步 API 的錯誤信息都是通過回調函數獲取的,支持 Promise 對象的異步 API 發生錯誤可以通過 catch() 方法捕獲。

異步函數執行如果發生錯誤要如何捕獲錯誤呢?

try catch 可以捕獲異步函數以及其他同步代碼在執行過程中發生的錯誤,但是不能捕獲其他類型的 API 發生的錯誤。

語法:

app.get('/', (req, res, netx) => {
  try {
    await User.find({name: '張三'});
  } catch (ex) {
    next(ex);
  }
});

例子:新建 06.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();
const fs = require('fs');
const promisify = require('util').promisify;
const readFile = promisify(fs.readFile);

app.get('/index', async (req, res, next) => {
  try {
    await readFile('./aaa.js')
  } catch (ex) {
    next(ex);
  }
})

// 錯誤處理中間件
app.use((err, req, res, next) => {
  res.status(500).send(err.message);
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

刷新瀏覽器,可以看到:

3、Express 請求處理

3.1、構建模塊化路由

基礎代碼:

const express = require('express');
// 創建路由對象
const home = express.Router();
// 將路由和請求路徑進行匹配
app.use('/home', home);
// 在 home 路由下繼續創建路由
home.get('/index', (req, res) => {
  // /home/index
  res.send('歡迎來到博客展示頁面');
});

例子:新建 07.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

// 創建路由對象
const home = express.Router();
// 為路由對象匹配請求路徑
app.use('/home', home);
// 創建二級路由
home.get('/index', (req, res) => {
  res.send('歡迎來到博客展示頁面');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 07.js

在瀏覽器中輸入:http://localhost:3000/home/index ,可以看到:

構建模塊化路由代碼:

// home
const home = express.Router();
home.get('/index', () => {
  res.send('歡迎來到博客展示頁面');
});
module.exports = home;

// admin
const admin = express.Router();
admin.get('/index', () => {
  res.send('歡迎來到博客管理頁面');
});
module.exports = admin;

// app.js
const home = require('./route/home.js');
const admin = require('./route/admin.js');
app.use('/home', home);
app.use('/admin', admin);

例子:在項目根目錄下新建 route文件夾,並新建 home.js 和 admin.js 文件:

// home.js
const express = require('express');
const home = express.Router();
home.get('/index', (req, res) => {
  res.send('歡迎來到博客展示首頁');
});
module.exports = home;

// admin.js
const express = require('express');
const admin = express.Router();
admin.get('/index', (req, res) => {
  res.send('歡迎來到博客管理首頁');
});
module.exports = admin;

新建 08.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();
const home
= require('./route/home'); const admin = require('./route/admin'); // 為路由對象匹配請求路徑 app.use('/home', home); app.use('/admin', admin); // 監聽端口 app.listen(3000); console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 08.js

打開瀏覽器輸入:http://localhost:3000/home/index  和 http://localhost:3000/admin/index ,可以看到:

3.2、GET參數的獲取

Express框架中使用 req.query 即可獲取 GET 參數,框架內部會將 GET 參數轉換為對象並返回。

示例代碼:

// 接收地址欄中問號后面的參數
// 例如: http://localhost:3000/?name=zhangsan&age=30
app.get('/', (req, res) => {
    console.log(req.query); // {"name": "zhangsan", "age": "30"}
});

例子:新建 09.js 文件:

// 引入 express 框架
const express = require('express');
// 創建網站服務器
const app = express();

app.get('/index', (req, res) => {
  // 獲取 get 請求參數
  res.send(req.query);
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 09.js

在瀏覽器中輸入:http://localhost:3000/index?name=zhangsan&age=30 ,可以看到:

3.3、POST 參數的獲取

Express 中接收 post 請求參數需要借助第三方包 body-parser

下載安裝:npm install body-parser

示例代碼:

// 引入 body-parser 模塊
const bodyParser = require('body-parser');
// 配置 body-parser 模塊
app.use(bodyParser.urlencoded({ extended: false }));
// 接收請求
app.post('/add', (req, res) => {
  // 接收請求參數
  console.log(req.body);
});

例子:

在命令行工具輸入:npm install body-parser

新建 10.js 文件:

// 引入 express 框架
const express = require('express');
// 引入 body-parser 模塊
const bodyParser = require('body-parser');
// 創建網站服務器
const app = express();

// 攔截所有的請求
// extended: false 方法內部使用 querystring 模塊處理請求參數的格式
// extended: true 方法內部使用第三方模塊 qs 處理請求參數的格式
app.use(bodyParser.urlencoded({ extended: false }))

app.post('/add', (req, res) =>{
  // 接收 post 請求參數
  res.send(req.body)
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 10.js

我們通過表單的形式來發送 post 請求,新建 post.html 文件:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <form method="POST" action="http://localhost:3000/add">
    <input name="username" type="text">
    <input name="password" type="password">
    <button type="submit">sbmit</button>
  </form>
</body>
</html>

右鍵點擊在瀏覽器中打開,然后隨便輸入一些信息,點擊提交,可以看到:

例子:新建 11.js 文件:

// 引入 express 框架
const express = require('express');
// 引入 body-parser 模塊
const bodyParser = require('body-parser');
// 創建網站服務器
const app = express();

app.use(fn ())

function fn() {
  return function (req, res, next) {
    console.log(req.method)
    next()
  }
}

app.get('/', (req, res) => {
  res.send('ok');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 11.js

在瀏覽器中輸入:http://localhost:3000/ ,可以看到:

 

這就證明了返回的函數 fn 被調用了。

這樣做的好處是:我們在調用 fn 函數的同時,向 fn 函數內部傳遞一些額外的參數;在請求處理函數內部,可以根據這個參數改變請求處理函數的行為。

修改 11.js 文件代碼:

// 引入 express 框架
const express = require('express');
// 引入 body-parser 模塊
const bodyParser = require('body-parser');
// 創建網站服務器
const app = express();

app.use(fn ({a: 1}))

function fn(obj) {
  return function (req, res, next) {
    if ( obj.a == 1) {
      console.log(req.url)
    } else {
      console.log(req.method)
    }
    next()
  }
}

app.get('/', (req, res) => {
  res.send('ok');
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

刷新瀏覽器,可以看到命令行工具中的:請求地址

如果把 app.use(fn ({a: 1})) 改為 app.use(fn ({a: 2}))

刷新瀏覽器,可以看到:請求方法

3.4、Express 路由參數

示例代碼:

app.get('/find/:id', (req, res) => { 
     console.log(req.params); // {id: 123} 
});
// 瀏覽器中打開 localhost:3000/find/123

例子:新建 12.js 文件:

// 引入 express 框架
const express = require('express');
// 引入 body-parser 模塊
const bodyParser = require('body-parser');
// 創建網站服務器
const app = express();

app.get('/index/:id', (req, res) => {
  res.send(req.params)
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具中輸入:nodemon 12.js

在瀏覽器中輸入:http://localhost:3000/index/123 ,可以看到:

如果是多個參數的話:

app.get('/index/:id/:name/:age', (req, res) => {
  res.send(req.params)
})

在瀏覽器中輸入:http://localhost:3000/index/123/zhangsan/20

 

3.5、靜態資源的處理

通過 Express 內置的 express.static 可以方便的托管靜態文件,例如 img、css、js 文件等。

app.use(express.static('public'));

現在 public 目錄下面的文件就可以訪問了。

例子:新建 13.js 文件:

// 引入 express 框架
const express = require('express');
const path = require('path');
// 創建網站服務器
const app = express();

app.use(express.static(path.join(__dirname, 'public')));

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在命令行工具輸入:nodemon 13.js

在瀏覽器中可以輸入相應的地址,訪問靜態資源。比如:

http://localhost:3000/images/1.jpg
http://localhost:3000/css/base.css
http://localhost:3000/default.html

4、express-art-template 模板引擎

4.1、模板引擎

為了使 art-template 模板引擎能夠更好的和 Express 框架配合,模板引擎官方在原 art-template 模板引擎的基礎上封裝了 express-art-template。

同時安裝這兩個,使用 npm install art-template express-art-template 命令進行安裝。

語法:

// 當渲染后綴為 art 的模板時,使用 express-art-template
app.engine('art', require('express-art-template'));
// 設置模板存放目錄
app.set('views', path.join(__dirname, 'views'));
// 渲染模板時不寫后綴,默認拼接 art 后綴
app.set('view engine', 'art');
app.get('/', (req, res) => {
  // 渲染模板
  res.render('index');
})

例子:

在命令行工具中下載安裝:

npm install art-template express-art-template

新建 14.js 文件:

// 引入 express 框架
const express = require('express');
const path = require('path');
// 創建網站服務器
const app = express();

// 1、告訴 express 框架使用什么模板引擎,渲染什么后綴的模板文件
// 第1個參數是模板的后綴
// 第2個參數是使用的模板引擎
app.engine('art', require('express-art-template'));
// 2、告訴 express 框架模板存放的位置是什么
app.set('views', path.join(__dirname, 'views'));
// 3、告訴 express 框架模板的默認后綴是什么
app.set('view engine', 'art');

app.get('/index', (req, res) => {
  // 拼接模板路徑
  // 拼接模板后綴、
  // 那一個模板和那個數據進行拼接
  // 將拼接的結果響應給客戶端
  res.render('index', {
    msg: 'message'
  })
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在項目根目錄下新建 views 文件夾,創建 index.art 文件:

{{ msg }}

在命令行工具中輸入:nodemon 14.js

在瀏覽器輸入:http://localhost:3000/index ,可以看到:

修改添加如下代碼:

// 引入 express 框架
const express = require('express');
const path = require('path');
// 創建網站服務器
const app = express();

// 1、告訴 express 框架使用什么模板引擎,渲染什么后綴的模板文件
// 第1個參數是模板的后綴
// 第2個參數是使用的模板引擎
app.engine('art', require('express-art-template'));
// 2、告訴 express 框架模板存放的位置是什么
app.set('views', path.join(__dirname, 'views'));
// 3、告訴 express 框架模板的默認后綴是什么
app.set('view engine', 'art');

app.get('/index', (req, res) => {
  // 拼接模板路徑
  // 拼接模板后綴、
  // 那一個模板和那個數據進行拼接
  // 將拼接的結果響應給客戶端
  res.render('index', {
    msg: 'message'
  })
})

app.get('/list', (req, res) => {
  res.render('list', {
    msg: 'list page'
  })
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

在路籃球中輸入:http://localhost:3000/list ,可以看到:

4.2、app.locals 對象

將變量設置到 app.locals 對象下面,這個數據在所有的模板中都可以獲取到。

示例代碼:

app.locals.users = [{
  name: '張三',
  age: 20
},{
  name: '李四',
  age: 20
}]

例子:新建 15.js 文件:

// 引入 express 框架
const express = require('express');
const path = require('path');
// 創建網站服務器
const app = express();

// 模板配置
app.engine('art', require('express-art-template'));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'art');

app.locals.users = [{
  name: '張三',
  age: 20
},{
  name: '李四',
  age: 30
}]

app.get('/index', (req, res) => {
  res.render('index', {
    msg: '首頁'
  })
})

app.get('/list', (req, res) => {
  res.render('list', {
    msg: '列表頁'
  })
})

// 監聽端口
app.listen(3000);
console.log('網站服務器啟動成功');

打開 views 目錄下的 index.art 和 list.art 文件,同時添加:

{{ msg }}

<ul>
  {{each users}}
  <li>
    {{$value.name}}
    {{$value.age}}
  </li>
  {{/each}}
</ul>

在命令行工具中輸入:nodemon 15.js

在瀏覽器輸入:http://localhost:3000/index 和 http://localhost:3000/list ,可以看到:

這就證明了 app.locals 這個對象下面的屬性,我們在所有的模板中都可以拿到。所以我們可以把項目中一些公共數據,添加到 app.locals 這個對象下面。

4.3、路由重定向 

res.redirect('/admin/user');

項目實例:博客項目

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM