UML 各種圖總結精華
1. 初識Express
1.1 Expres簡介
-
什麼是 Express
- 概念:Express 是基於 Node.js 平臺,快速、開放、極簡的 Web 開發框架。
- 本質:第三方包,提供了快速建立 Web 伺服器的便捷方法。
-
Express 的作用
對於前端來說,最常見的兩種伺服器,分別是:- Web 網站伺服器:專門對外提供web網專資源的伺服器。
- API介面伺服器:專門對外提供API介面的伺服器。
使用 Express,可以方便、快速建立Web網站的伺服器或API介面的伺服器。
1.2 Express的基本使用
-
執行
npm i [email protected]
命令安裝 express -
建立基本的Web伺服器
// 1. 匯入 express const express = require('express'); // 2. 建立 Web 伺服器例項物件 const app = express(); // 3. 定義埠號 const port = 3000; // 4. 呼叫app.listen(埠號,啟動成功後的回撥函式) 方法,啟動伺服器 app.listen(port, () => { console.log('Express server running at http://127.0.0.1:3000'); })
-
監聽GET請求語法格式
/* * @alias app.get(url, callback) * @param {string} 客戶端請求的URL地址 * @param {callback} 響應客戶端請求的處理函式 */ app.get('url', (req, res) => { // req: 請求物件(包含了與請求相關的屬性與方法) // res: 相應物件(包含了與響應相關的屬性與方法) // 處理函式體 })
-
監聽POST請求語法格式
/* * @alias app.post(url, callback) * @param {string} 客戶端請求的URL地址 * @param {callback} 響應客戶端請求的處理函式 */ app.post('url', (req, res) => { // req: 請求物件(包含了與請求相關的屬性與方法) // res: 相應物件(包含了與響應相關的屬性與方法) // 處理函式體 })
-
獲取URL中攜帶的查詢引數
通過req.query
物件,可以訪問到客戶端通過查詢字串的形式傳送到伺服器的引數:app.get('/search', (req, res) => { // req.query 預設是一個空物件 // 當客戶端的請求URL為:/search?q=taobao console.log(req.query); // 輸出: { q: 'taobao' } console.log(req.query.q); // 輸出: taobao })
-
獲取表單中的資料
通過req.body
物件,可以獲取表單提交過來的資料:// 如果需要使用 req.body , 需要在使用前使用解析表單的中介軟體(下面會詳細說) app.use(express.urlencoded({ extended: true })); // 如果使用上述程式碼,req.body 的值為 undefined app.post('/reg', (req, res) => { console.log(req.body); })
-
獲取URL中的動態引數
通過req.params
物件,可以訪問到URL中通過:
匹配到的動態引數:// :id 表示 id 這個引數是動態引數 app.get('/user/:id', (req, res) => { // req.params 預設是一個空物件 // 客戶端請求URL為: /user/34 console.log(req.params); // 輸出: { id: '34' } })
-
響應客戶端請求
通過res.send()
方法,可以把資料和資訊傳送給客戶端。app.get('/', (req, res) => { // 向客戶端傳送 JSON 物件 res.send({ name: 'xao', age: 18, sex: '男', }); }) app.post('/user', (req, res) => { // 向客戶端傳送文字內容 res.send('POST請求成功'); })
1.3 託管靜態資源
- 靜態資源目錄樹結構
|--public |--|--index.html |--|--login.html |--|--register.html
-
express.static()
通過使用express.static()
方法,可以快速建立一個靜態資源伺服器。app.use(express.static('./public')); // 通過上述程式碼,客戶端就可以訪問public目錄下的靜態資源 // htpp://127.0.0.1:3000/index.html // htpp://127.0.0.1:3000/login.html // htpp://127.0.0.1:3000/register.html
-
託管多個靜態資源目錄
如果要託管多個靜態資源目錄,請多次呼叫express.static() 方法app.use(express.static('./public')); app.use(express.static('./files'));
客戶端訪問靜態資源時,express.static() 函式會根據目錄的新增順序查詢所需的檔案。
-
掛載路徑字首
如果希望在託管的靜態資源訪問路徑之前,掛載路徑字首,則可以使用如下的方式:app.use('/public',express.static('./public')); // 新增上述程式碼後,客戶端訪問資源時必須要帶有 /public 字首地址來訪問public目錄中的靜態資源 // htpp://127.0.0.1:3000/public/index.html // htpp://127.0.0.1:3000/public/login.html // htpp://127.0.0.1:3000/public/register.html
2. Express 路由
2.1 路由的概念
-
從廣義上來講,路由就是對映關係。
-
express 中的路由
- 在 express 中,路由指的是 客戶端的請求 與 伺服器處理函式 之間的對映關係。
- express 中的路由分 3 部分組成,分別是 請求的型別、 請求的 URL 地址、 處理函式 。
-
具體程式碼
// 匹配GET請求,且請求 URL 地址為 /index.html app.get('/index.html', (req, res) => { res.send('hello world !'); }) // 匹配POST請求,且請求 URL 地址為 /login.html app.post('/login.html', (req, res) => { res.send('登入成功'); })
-
express路由匹配過程
- 每當一個請求到達伺服器之後,需要先經過路由的匹配,只有匹配成功之後,才會呼叫對應的處理函式。
- 在匹配時,會按照路由定義的順序進行匹配,如果請求型別和請求的 URL 同時匹配成功,則 Express 會將這次請求,轉交給對應的 function 函式進行處理。
2.2 路由的使用
-
簡單使用方法
將路由掛載到伺服器例項物件上// 匯入 express const express = require('express') // 建立 web 伺服器例項物件 const app = express() // 定義埠號 const port = 3000 // 掛載路由 app.get('/', (req, res) => { res.send('GET request to the homepage') }) app.post('/', function (req, res) { res.send('POST request to the homepage') }) // 啟動伺服器 app.listen(port, () => { console.log(`Express server running at http://127.0.0.1:3000`) })
-
模組化路由
為了方便對路由進行模組化的管理,Express 不建議將路由直接掛載到 app 上,而是推薦將路由抽離為單獨的模組。-
將路由抽離為單獨模組的步驟如下:
- 建立路由模組對應js檔案
- 呼叫 express.Router() 函式建立路由物件
- 定義路由的具體對映關係
- 使用 module.exports 向外共享路由物件
- 使用 app.use() 函式註冊路由模組
-
程式碼如下
- 建立路由模組
// 匯入 express const express = require('express'); //建立路由物件 const router = express.Router(); // 定義路由的對映關係 router.get('/', (req, res) => { res.send('GET request to the homepage') }) router.post('/', function (req, res) { res.send('POST request to the homepage') }) // 向外共享路由物件 module.exports = router;
- 註冊路由模組
// 匯入路由模組 const router = require('./router.js'); // 使用 app.use() 註冊路由模組 app.use(router);
- 為路由模組新增路徑字首
// 使用 app.use() 註冊路由模組,並統一新增訪問路徑字首 app.use('/index', router);
- 建立路由模組
-
3. Express 中介軟體
3.1 中介軟體的概念
-
中介軟體(Middleware ),特指業務流程的 中間處理環節。
-
express 中介軟體的呼叫流程
- 當一個請求到達伺服器之後,可以連續呼叫多箇中間件,從而對這次請求進行預處理。
- 多箇中間件之間共享 req 和 res 物件。
- 當處理完畢後,響應客戶端的請求。
3.2 中介軟體的型別
-
應用層中介軟體
通過 app.use() 和 app.METHOD() 函式,繫結到 express() 例項物件上的中介軟體,叫做應用層中介軟體。const app = express(); // 每次收到請求,都會執行該中介軟體(全域性中介軟體) app.use((req, res, next) => { console.log('hello express !'); next(); // next() 方法必須被呼叫,以便進入下一個中介軟體。否則,請求將被掛起。 // 呼叫 next() 方法之後,不要再書寫任何程式碼。(一般最後呼叫 next() 方法) }) // 該中介軟體只會在客戶端請求 /api 路徑時,被執行 app.use('/api', (req, res, next) => { console.log('api'); next(); }) // 該中介軟體只會在客戶端發起 GET 請求,且請求 /public 路徑時被執行 app.get('/public', (req, res, next) => { console.log('public'); next(); })
-
路由級中介軟體
路由器級中介軟體與應用層中介軟體的工作方式相同,只不過它繫結到的例項 express.Router() 上。const userRouter = express.Router(); // 該中介軟體只會在客戶端請求 userRouter 模組時被執行 userRouter.use((req, res, next) => { console.log('success'); next(); }) // 該中介軟體只會在客戶端請求 userRouter 模組,且請求路徑為 /userinfo 時被執行 userRouter.use('/userinfo', (req, res, next) => { console.log('userinfo'); next(); }) // 該中介軟體只會在客戶端請求 userRouter 模組,發起 POST 請求,且路徑為 /userinfo/update 時被執行 userRouter.post('/userinfo/update', (req, res, next) => { console.log('update userinfo'); next(); })
-
錯誤處理中介軟體
- 錯誤中介軟體必須帶有4個引數,(err, req, res, next)
- 錯誤中介軟體無需呼叫 next() 方法,但引數必須傳;否則,會被當做其他型別的中介軟體執行。
- 錯誤中介軟體必須在所有路由之後呼叫
app.use((err, req, res, next) => { if(req.url == '/api/info') { return res.status(404).send('404 頁面不存在!'); } res.status(500).send('伺服器內部錯誤'); })
-
內建中介軟體
express.static
快速託管靜態資源的內建中介軟體,例如: HTML 檔案、圖片、CSS 樣式等(無相容性)。express.json
解析 JSON 格式的請求體資料(有相容性,4.16.0+ 中可用)。express.urlencoded
解析 URL-encoded 格式的請求體資料(有相容性,4.16.0+ 中可用)。
-
第三方中介軟體(與包類似)
- 非express官方內建的中介軟體,而是有第三方開發出來的express中介軟體,叫做第三方中介軟體。
- 使用第三方中介軟體時,需要使用
npm i 名稱
下載第三方中介軟體,使用require()
匯入,並呼叫app.use()
掛載第三方中介軟體。
3.3 自定義中介軟體
// 新建一個js檔案
// 自定義模組可以使用 node.js 內建模組 或 第三方模組
// 定義中介軟體
const myMiddle = (req, res, next) => {
// 要執行的程式碼...
next();
}
// 向外共享myMiddle
module.exports = myMiddle;
4. 使用過 express 搭建API介面伺服器
4.1 使用過 express 搭建API介面
-
搭建基本伺服器
// 匯入 express const express = require('express'); // 建立伺服器例項物件 const app = express(); // 定義埠號 const port = 3000; // 匯入路由模組 const apiRouter = require('./apiRouter'); // 將路由模組註冊到伺服器上 app.use('/api', apiRouter); app.listen(port, () => console.log(`Example server running at http://127.0.0.1:3000`));
-
apiRouter 模組
// 匯入 express const express = require('express'); // 建立一個新的路由物件 const router = express.Router(); // 實現路由的對映 router.get('/get', (req, res) => { const query = req.query; res.send({ status: 200, // 響應狀態碼:200 msg: 'GET請求成功', // 響應狀態描述 data: query, // 響應給客戶端的資料 }); }); router.post('/post', (req, res) => { const query = req.query; res.send({ status: 200, // 響應狀態碼:200 msg: 'POST請求成功', // 響應狀態描述 data: query, // 響應給客戶端的資料 }) }) // 向外共享路由模組 module.exports = router;
4.2 跨域資源共享
-
CORS(Cross-Origin Resource Sharing)跨域資源共享
- 同源:客戶端請求的URL地址與伺服器的ULR地址的協議、域名、埠號都相同即為同源,三者有一者不同為跨域。
- 由於瀏覽器同源策略的存在,預設阻止跨域獲取資源;但伺服器可以通過設定響應頭,允許跨域請求訪問資源。
- 但CORS 在瀏覽器中有相容性,只支援 XMLHttpRequest Level2 的瀏覽器,才能正常開啟 CORS (例如:IE10+、Chrome4+、FireFox3.5+)。
-
CORS 跨域資源實現方式
通過指定響應頭Access-Control-Allow-Origin
欄位對應的值來指定允許訪問資源的外域 URL。// 只允許來自 http://127.0.0.1:5500 的跨域訪問資源請求 res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500'); // 值為 '*' : 表示允許來自任何域的請求 res.setHeader('Access-Control-Allow-Origin', '*');
-
CORS 預設支援9個請求頭
Accept Accept-Language Content-Language DPR Downlink Save-Data Viewport-Width Width Content-Type (值僅限於 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
如果需要支援其他的型別的請求頭,可以通過
Access-Control-Allow-Headers
欄位對額外的請求進行宣告。// 允許客戶端額外向伺服器傳送 X-Custom-Header 請求頭 res.setHeader('Access-Control-Allow-Headers', 'X-Custom-Header'); // 可以同時設定多個請求頭,多個請求頭之間用英文逗號分隔 res.setHeader('Access-Control-Allow-Headers','Content-Type,X-Custom-Header');
-
CORS 預設情況下僅支援客戶端發起的簡單請求(GET、POST、HEAD)。
如果伺服器想要允許客戶端通過非簡單請求(預檢請求)來請求服務端的資源,可以通過Access-Control-Alow-Methods
欄位來設定客戶端可以使用的請求方式。// 允許客戶端使用 GET, POST, HEAD, DELETE 方式請求資源 res.setHeader('Access-Control-Alow-Methods', 'GET, POST, HEAD, DELETE'); // 允許客戶端使用所有的HTTP請求方式 res.setHeader('Access-Control-Alow-Methods', '*');
-
簡單請求
- 請求方式為 GET、POST、HEAD 三者之一。
- 客戶端請求頭部無自定義頭部欄位。
- 客戶端只會向服務端傳送一次請求。
-
預檢請求
- 請求方式為 GET、POST、HEAD 之外的請求型別。
- 請求頭部包含自定義頭部欄位。
- 向伺服器傳送
application/json
格式的資料。 - 客戶端會向伺服器傳送兩次請求。
- 在瀏覽器與伺服器正式通訊之前,瀏覽器會先發送 OPTION 請求進行預檢,以獲知伺服器是否允許該實際請求。
- 伺服器成功響應OPTION請求(預檢請求)後,才會傳送真正的請求,並且攜帶真實資料。
4.3 跨域解決方案
- CORS(主流方案,只需要在後端配置,推薦使用)
- JSONP(相容性好,需要前後端配合,但只支援GET請求)
4.4 使用 cors 中介軟體解決跨域問題
cors 是 express 的一個第三方中介軟體,通過安裝和配置中介軟體,可以方便解決跨域問題。
- 安裝:
npm i cors
- 匯入:
const cors = require('cors')
- 全域性配置:
app.use(cors())
4.5 使用 jsonp 解決跨域問題
- 伺服器端程式碼
app.get('/api/jsonp', (req, res) => { // 1. 得到函式的名稱 const funName = req.query.callback // 2. 定義要傳送到客戶端的資料物件 const data = { name: 'zs', age: 22 } // 3. 拼接出一個函式的呼叫 const scriptStr = `${funName}(${JSON.stringify(data)})` // 4. 把拼接的字串,響應給客戶端 res.send(scriptStr) })
- 客戶端程式碼
$.ajax({ type: 'GET', url: 'http://127.0.0.1/api/jsonp', dataType: 'jsonp', success: function (res) { console.log(res); } })
PS: 如果本文對你有所幫助,請點個贊吧!