Express
什麼是 Express ?
- Express 是一個基於 Node.js 封裝的上層服務框架,它提供了更簡潔的 API, 更實用的新功能
- Express通過中間件和路由讓程序的組織管理變的更加容
- Express提供了豐富的 HTTP 工具, 它讓動態視圖的渲染變的更加容易, 此外, 還定義了一組可拓展標準
- Express是目前最流行的node.js後端框架之一, 相當於jQuery和js之間的關係
- Express 不對 Node.js 已有的特性進行二次抽象,我們只是在它之上擴展了 Web 應用所需的基本功能
- 功能類似的後端框架:Koa.js, egg.js
爲什麼要使用Express?
- nodejs提供了的方法處理起來比較麻煩,在使用nodejs時有很多現成的框架幫助開發人員,其中最簡單的一個server框架就是Express
- 兩種使用方式
① 在項目文件夾中安裝express
② 通過express的generator來生成一個express的骨架
安裝express
- 進入應用目錄
npm init
命令爲你的應用創建一個 package.json 文件- 安裝 Express 並將其保存到依賴列表中
npm install express --save
- 如果只是臨時安裝 Express,不想將它添加到依賴列表中,只需略去 --save 參數即可
npm install express
- Express 應用生成器
通過應用生成器工具 express 可以快速創建一個應用的骨架。
① 安裝
npm install express-generator -g
② 常用操作
express -h
-h 選項可以列出所有可用的命令行選項
安裝所有依賴包
npm install
③ 設置視圖模板
express --view=ejs demo1
④ 啓動應用
MacOS 或 Linux 平臺
DEBUG=myapp npm start
Windows 平臺
set DEBUG=myapp & npm start
在瀏覽器中打開 http://localhost:3000/ 網址就可以看到這個應用了
⑤ 通過 Express 應用生成器創建的應用一般都有如下目錄結構
中間件
中間件是如何工作的?
-
原生Node中, http請求/響應處理都在一個函數中
① 代碼let requestHandler = (request, response) => { console.log("In comes a request to: " + request.url); response.end("Hello, world!"); }
② 圖示
注意
這並不是說在處理過程中不能調用其它函數,而是所有的請求響應都由該函數發送 -
中間件則使用一組中間件棧函數來處理這些請求
① 圖示
② 作用
用來處理 http 請求的一個具體的環節(可能要執行某個具體的處理函數)
中間件一般都是通過修改 req 或者 res 對象來爲後續的處理提供便利的使用
③ 注意
任何請求進來都會執行對應的處理函數
不關心當前請求的具體請求方法和請求路徑
中間件分類?
use(‘請求路徑’, (req, res, next)=>{})
get(‘請求路徑’, (req, res, next)=>{})
post(‘請求路徑’, function (req, res, next) {})
第三方中間件類庫
- MORGAN:日誌記錄中間件
- 安裝
npm install morgan --save
- Express 的靜態文件中間件
- 安裝
實操
- 在 http 中,沒有請求就沒有響應,服務端不可能主動給客戶端返回響應,就是一問一答的形式
- 對於一次請求來說,只能響應一次,如果發送了多次響應,則只有第一次生效
next()是執行下一個路由
// 1. 引入 const express = require('express'); const fs = require('fs'); const path = require('path'); // 2. 創建web服務器 const app = express(); // 4. 寫日誌 app.use((req, res, next)=>{ const log = ` ---------------------------------------- 1) 請求的方式: ${req.method}, \n 2) 請求的路徑: ${req.url}, \n 3) 請求的時間: ${new Date()}, \n ---------------------------------------- `; // 寫入文件 fs.appendFile(path.join(__dirname, 'req.log'), log, (err)=>{ if(err) throw err; next(); }); }); // 加入很多很多中間件 app.use((req, res, next)=>{ console.log('1111111'); next(); }); app.use((req, res, next)=>{ console.log('2222222'); next(); }); app.use((req, res, next)=>{ console.log('333333'); next(); }); app.get('/', (req, res, next)=>{ res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'}); res.write('<h2>Hello, World!</h2>'); next(); }); app.get('/', (req, res)=>{ res.write('<h2>您好,撩課學院!</h2>'); res.end(); }); // 3. 開啓監聽 app.listen(3000, ()=>{ console.log('服務器已經啓動!'); });
Express重點操作
-
Hello World
// 1. 引入 const express = require('express'); // 2. 調用 express() 方法,得到一個 app 實例接口對象 //(類似於 http.createServer 得到的 server 實例) const app = express(); // 3. 通過 app 根據路徑處理 get 和 post 請求 app.get('/', (req, res)=>{ res.write('<h1>hello</h1>'); res.end() }); app.get('/itlike', (req, res)=>{ res.end('<h1>hello, itLike</h1>') }); // 4. 開啓監聽,啓動服務器 app.listen(3000, () => { console.log('服務已經啓動!') });
-
靜態資源文件
app.use('/public', express.static('開放目錄的路徑'))
在 use 方法中,如果指定了第一個路徑參數,則通過 req.path 獲取到的是不包含該請求路徑的字符串
例如當前請求路徑是 /public/test.jpg, 則通過 req.path 拿到的就是 test.jpg
使用app.use('/static', express.static(path.join(__dirname, 'static')));
-
錯誤/異常統一處理
Express 使用模板引擎
const express = require('express');
const path = require('path');
const app = express();
// 註冊模板引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.get('/', (req, res)=>{
const dataJson = {
"lists":[
{"title": "撩課學院1週年慶倒計時", "count": 675593, "up": 1},
{"title": "女演員全美善自殺", "count": 634434, "up": 1},
{"title": "哈登騎電動車被抓", "count": 623323, "up": 0},
{"title": "吃酸辣粉被罰款", "count": 546767, "up": 0},
{"title": "蔚來汽車莊莉離職", "count": 536237, "up": 1},
{"title": "父母抓鬮陪女兒", "count": 525193, "up": 0},
{"title": "宋仲基爸爸短信", "count": 475593, "up": 0},
{"title": "宋仲基爸爸短信", "count": 375593, "up": 1},
{"title": "今天天氣很好", "count": 275593, "up": 1}
],
"source": "撩課風雲榜 - itLike.com"
};
res.render('list', dataJson);
});
app.listen(3000, ()=>{
console.log('服務器已經啓動');
});
統一的錯誤處理日誌中間件
app.use((err, req, res, next)=>{
const error_log = `
=====================================
錯誤名: ${err.name}, \n
錯誤信息:${err.message}, \n
錯誤時間:${new Date()}, \n
錯誤堆棧:${err.stack}, \n
=====================================
`;
fs.appendFile(path.join(__dirname, 'error.log'), error_log, (err)=>{
res.writeHead(500, {'Content-Type': 'text/html;charset=utf-8'});
res.end('500 服務器內部錯誤!')
});
});
Express 應用生成器(腳手架)
通過應用生成器工具 express 可以快速創建一個應用的骨架。
安裝
npm install express-generator -g
-g全局安裝
常用操作
express -h
-h 選項可以列出所有可用的命令行選項
安裝所有依賴包
npm install
設置視圖模板
express demo1 --view=ejs
啓動應用
MacOS 或 Linux 平臺
DEBUG=myapp npm start
Windows 平臺
set DEBUG=myapp & npm start
在瀏覽器中打開 http://localhost:3000/ 網址就可以看到這個應用了
通過 Express 應用生成器創建的應用一般都有如下目錄結構
app.js
// 1.引入所有的包依賴文件
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
// 2. 引入路由文件
const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');
// 3. 創建web服務器
const app = express();
// 4. 設置模板引擎
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// 5. 使用各種中間件
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// 6. 配置路由
app.use('/', indexRouter);
app.use('/users', usersRouter);
// 處理找不到頁面
app.use(function(req, res, next) {
next(createError(404));
});
// 統一處理錯誤
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
7) socket.io
socket.io 是什麼?
- Socket.io 將 Websocket 和輪詢( Polling )機制以及其它的實時通信方式封裝成了通用的接口,並且在服務端實現了這些實時機制的相應代碼。
- H5 的新技術 Websocket 僅僅是 Socket.io 實現實時通信的一個子集。
如何使用socket.io?
- 安裝
npm install socket.io --save
進入 package.json 所在的目錄下, 運行上面命令 - 引入
// 引入包
let socketPackage = require('socket.io');
// 針對 http server 生成 socket.IO 實例對象
let io = socketPackage(server);
使用 socket.IO 的時候,需要生成一個 實例對象;
生成這個實例對象的依賴原生 node 已經建立好的 httpServer 對象
常用API?
服務器端
-
監聽連接
io.on('connection',function(socket));
當有客戶端向本服務器建立連接的時候, ‘connection’ 事件就被激發。對應的回調函數就會執行。回調函數的參數 socket 就是這個客戶端與服務器的 連接對象
-
給所有客戶端廣播消息
io.sockets.emit('String',data);
服務器主動向客戶端發送消息, 消息的事件名爲 myEvnetLabel , 消息的具體內容爲 data
-
給指定的客戶端廣播消息
io.sockets.socket(socketid).emit('String', data);
-
監聽客戶端消息
socket.on(‘myEvnetLabel’,function(data){});
當某個客戶端向服務器發送消息的時候,服務器監聽這個消息,並將其回調函數執行
瀏覽器端
-
開啓連接
let url = 'http://localhost:3000'; let socket = io.connect(url);
-
監聽服務器的消息
socket.on('myEvnetLabel',function(data){});
當服務器有消息到達的時候,回調函數會被激發
- 向服務器發送消息
socket.emit(‘myEvnetLabel’, data);
客戶端主動向服務器發送消息, 消息的事件名爲 myEvnetLabel , 消息的具體內容爲 data
客戶端socket.on()監聽的事件
connect:連接成功
connecting:正在連接
disconnect:斷開連接
connect_failed:連接失敗
error:錯誤發生,並且無法被其他事件類型所處理
message:同服務器端message事件
anything:同服務器端anything事件
reconnect_failed:重連失敗
reconnect:成功重連
reconnecting:正在重連
當第一次連接時,事件觸發順序爲:connecting->connect;當失去連接時,事件觸發順序爲:disconnect->reconnecting(可能進行多次)->connecting->reconnect->connect。