日誌中介軟體
// 掛載會每個介面都執行這段程式碼
app.use((req,res,next)=>{
console.log(req.method,req.url,Date.now())
next() //下一個中介軟體
})
2.中介軟體的順序很重要
如果有一個普通介面寫在上面程式碼之前,那麼就不會進入上面的函式中
但是如果在介面中第二個回撥函式的引數中加入next,則可以進入
// 不會列印時間戳及相關資訊
app.get("/todos", async (req, res) => {
try {
const db = await getDB();
res.status(200).json(db.todos);
} catch (err) {
return res.status(500).json({ error: err.message });
}
});
// 可以列印了~
app.get("/todos", async (req, res, next) => {
try {
const db = await getDB();
res.status(200).json(db.todos);
next()
} catch (err) {
return res.status(500).json({ error: err.message });
}
});
我是講武德的,這些課件截圖源於b站up主小打小鬧Studio
https://space.bilibili.com/13625996
在中介軟體函式中可以執行以下任何任務:
1).執行任何程式碼
2).修改request或response響應物件
3).結束請求響應週期
4).呼叫下一個中介軟體
如果當前的中介軟體功能沒有結束請求-響應週期,則必須使用next()將控制權傳遞給下一個中介軟體功能。否則,該請求將被掛起。
2.Express中介軟體分類:
1)應用程式級別中介軟體 express例項.xxx
2)路由級別中介軟體 express.Router()
3)錯誤處理中介軟體 和其他中介軟體函式一樣,但是四個引數
4)內建中介軟體
5)第三方中介軟體
1)透過Express例項掛載的中介軟體
a)不做任何限定的中介軟體
app.use((req, res, next) => {
console.log(req.method, req.url, Date.now());
next(); //下一個中介軟體
});
b)限定請求方法+請求路徑的中介軟體
就是符合條件的APi被呼叫後才會進入這個中介軟體
//限定請求路徑
app.use('/task',(req, res, next) => {
console.log(req.method, req.url, Date.now());
next(); //下一個中介軟體
});
app.get('/task',(req, res, next) => {
res.status(200).send('是否會進入?')
})
//----頁面進入/task中介軟體去列印方法和時間戳也會有‘是否進入’
//限定請求路徑
app.use('/aaa',(req, res, next) => {
console.log(req.method, req.url, Date.now());
next(); //下一個中介軟體
});
//---這種就是不會進入列印了,因為匹配不上了
c)多個處理函式
app.use(
"/",
(req, res, next) => {
console.log(req.method, req.url, Date.now());
next();
},
(req, res, next) => {
console.log('也會進來嗎');
// next(); //如果註釋掉就不會進入下面的介面了
}
);
app.get("/", (req, res, next) => {
res.status(200).send("是否會進入?");
});
d)next('route') 下一步進入請求,而不是普通下一步
app.get(
"/user/:id",
function (req, res, next) {
console.log(req.method, req.url, Date.now());
console.log(typeof(req.params.id),'999')
if (req.params.id === '2') {
next("route"); //跳過也會進來嗎函式的執行,直接進入是否會進入
} else {
next(); //繼續往下執行
}
},
function (req, res, next) {
console.log("也會進來嗎");
next();
}
);
app.get("/user/:id", (req, res, next) => {
res.status(200).send("是否會進入?");
});
2)路由級別中介軟體
每個請求都需要app.xxx太過於繁瑣 ,可以使用路由例項 相當於mini express 例項
後續就透過router.xxx()
a)根目錄下建立一個router.js 檔案,建立一個router例項
const express = require('express')
const router = express.Router()
b)配置路由
router.get('/',(req,res,next)=>{})
c) 匯出路由例項
module.exports = router
d)將路由整合/掛載到Express例項應用中
const router = require('./router);
app.use(router)
//app.use('/abc',router) //在所有的路由前面都叫上限定訪問的字首
//可以將在app.js中寫的所有路由配置放到router.js去
3)錯誤處理中介軟體
與其他中介軟體函式相同的方式定義錯誤處理中介軟體函式,除了使用四個引數而不是三個引數,一定是四個引數
一般在所有的中介軟體之後掛載錯誤處理函式中間件
app.use((err,req,res,next)=>{
console.log(err.stack)
res.status(500).json({error:err.message})
})
在try catch中的catch裡面使用next(err),傳遞錯誤的資訊,跳過所有剩餘的非錯誤處理路由和中介軟體函式,其實就是報錯之後去觸發錯誤處理函式,然後就結束任務
在router.js中將前面的所有路由中介軟體的catch裡面都修改成next(err)
router.post("/todos", async (req, res,next) => {
try {
const db = await getDB();
const reqBd = req.body;
if (!reqBd.title) {
return res.status(422).send({ error: "The field title is required" });
}
const lastTodoItem = db.todos[db.todos.length - 1];
db.todos.push({
id: lastTodoItem ? lastTodoItem.id + 1 : 1,
title: reqBd.title,
});
await saveDB(db);
res.status(200).send("新增成功!");
} catch (err) {
next(err);
}
});
模擬一下報錯的場景,正常可以響應500與對應的錯誤資訊
通常我們會在最後的位置放置一個404的處理中介軟體函式,其實出現404的時候也有一個預設的html提示樣式介面
404 與500型別的中介軟體沒有先後的影響,會對應觸發,但是其餘會依此從上往下執行
app.use((req,res,next)=>{
res.status(404).send('404 not found)
})
4)內建中介軟體
express.json() ---application/json
express.urlencoded() ---application/x-www-form-urlcoded
express.raw() ---application/octet-stream
express.text() ---text/plain
express.static() ---託管靜態資原始檔
5)第三方中介軟體
為了極簡靈活的特性,epxress4之後將很多的中介軟體進行獨立 ----middleware module
看文件使用即可
https://expressjs.com/zh-cn/resources/middleware.html
demo使用這些第三方中介軟體~~ 日誌輸出中介軟體
a)裝包 npm install morgan
b)引入 var morgan = require('morgan')
c)掛載 app.use(morgan('tiny'))