一、前言
上篇文章我們介紹了express-generator的請求體解析,重點講了常用的請求體數據格式(JSON/URL 編碼的表單數據)以及一個FILE文件上傳,同時搭配代碼示范進行輔助理解。
二、本篇重點
我們繼續第一階段的知識,本篇把最后兩個知識點(路由中間件和錯誤請求)講完,順利完成第一階段的初步認識和學習。
三、知識點:路由中間件
1、路由中間件是什么?
路由中間件是 Express 中的一個強大功能,它允許你在處理請求之前和之后執行自定義邏輯。中間件可以用于各種任務,如日志記錄、身份驗證、數據驗證等。?
?路由中間件可以被理解為一個函數,它接收三個參數:
req
(請求對象)、res
(響應對象)和next
(函數)。這個函數可以對這三個參數進行操作,并且通過這些操作來影響 Express 服務器的行為。以下是路由中間件的一些關鍵點:
接收參數:
req
(請求對象):包含了請求的所有信息,如請求方法、URL、請求頭、請求體等。中間件可以讀取和修改?req
?對象的屬性。res
(響應對象):用于向客戶端發送響應。中間件可以發送響應、設置響應頭、設置響應狀態碼等。next
(函數):調用?next()
?可以將控制權傳遞給下一個中間件或路由處理函數。如果不調用?next()
,請求處理流程將停止。操作和影響:
- 讀取和修改請求信息:中間件可以讀取請求中的數據,如解析請求體、獲取請求頭信息等。也可以修改請求對象,如添加自定義屬性、修改請求參數等。
- 發送響應:中間件可以直接向客戶端發送響應,結束請求處理流程。例如,可以發送錯誤響應、重定向響應等。
- 執行自定義邏輯:中間件可以執行各種自定義邏輯,如身份驗證、日志記錄、數據驗證、緩存處理等。
- 錯誤處理:中間件可以捕獲和處理錯誤,將錯誤傳遞給錯誤處理中間件,或者直接發送錯誤響應。
?中間件的執行順序
- 順序執行:中間件按照它們在?
app.use()
?中被調用的順序執行。每個中間件都有機會處理請求,并決定是否將控制權傳遞給下一個中間件。- 調用?
next()
:中間件通過調用?next()
?函數來將控制權傳遞給下一個中間件。如果中間件不調用?next()
,請求處理流程將停止,不會執行后續的中間件或路由處理函數。
2、express-generator創建express應用程序,默認使用的路由中間件
?首先讓我們看看使用express-generator創建一個express應用程序時,app.js默認使用的路由中間件有哪些
知識點相關介紹:?
1.?
logger('dev')
- 作用:使用?
morgan
?日志記錄器中間件,記錄 HTTP 請求的詳細信息。- 配置:
'dev'
?是?morgan
?的預定義格式之一,它會在開發環境中提供簡潔的彩色日志輸出,包括請求方法、URL、響應狀態碼和響應時間等。- 使用場景:用于開發環境中的日志記錄,幫助開發者監控和調試應用程序。
2.?
express.json()
- 作用:解析 JSON 格式的請求體。
- 使用場景:用于處理客戶端發送的 JSON 數據,例如 API 請求中的 JSON 數據。
3.?
express.urlencoded({ extended: false })
- 作用:解析 URL 編碼的請求體。
- 配置:
{ extended: false }
?表示使用內置的查詢字符串解析器,它只能解析簡單的鍵值對,不支持嵌套對象或數組。- 使用場景:用于處理 HTML 表單提交的數據,這些數據通常以?
application/x-www-form-urlencoded
?格式發送。4.?
cookieParser()
- 作用:解析客戶端發送的 Cookie。
- 使用場景:用于處理客戶端發送的 Cookie,以便在服務器端進行身份驗證或其他需要 Cookie 的操作。
5.?
express.static(path.join(__dirname, 'public'))
- 作用:提供靜態文件服務。
- 配置:
path.join(__dirname, 'public')
?指定了靜態文件的目錄,通常是項目的?public
?目錄。- 使用場景:用于提供網站的靜態資源,如圖片、CSS、JavaScript 文件等,使得客戶端可以直接訪問這些文件。
?3、動手寫一個簡單的路由中間件
const express = require('express');
const app = express();// 定義一個日志記錄中間件
function logRequest(req, res, next) {const { method, url } = req;console.log(`Received ${method} request for ${url}`);next(); // 調用下一個中間件
}// 使用中間件
app.use(express.json()) //解析請求體數據
app.use(logRequest); //日志記錄中間件
app.get('/', (req, res) => {res.send('Hello, World!');
});
app.post('/user', (req, res) => {console.log("接收的請求體參數>>>",req.body);res.send(req.body);});app.listen(3009, () => {console.log('Server is running on port 3009');
});
?啟動服務器,打開apipost工具進行路由測試
?在這個示例中,
logRequest
中間件會在每個請求到達時記錄請求方法和 URL。
四、知識點:錯誤處理
錯誤處理是任何 Web 應用程序的重要組成部分。在 Express 中,錯誤處理中間件用于捕獲和處理在請求處理過程中發生的錯誤。
常用知識點
- 錯誤處理中間件:必須有四個參數:
err
、req
、res
?和?next
。- 拋出錯誤:在中間件或路由處理函數中使用?
next(err)
?來傳遞錯誤。- 自定義錯誤對象:可以創建自定義錯誤對象以提供更詳細的錯誤信息。
?1、常見的錯誤類型
- 語法錯誤:由于代碼編寫錯誤導致的錯誤,如拼寫錯誤、語法不正確等。
- 運行時錯誤:在代碼執行過程中發生的錯誤,如訪問未定義的變量、調用不存在的方法等。
- HTTP 錯誤:與 HTTP 請求和響應相關的錯誤,如 404(未找到)、500(服務器內部錯誤)等。
- 輸入驗證錯誤:由于用戶輸入不符合預期格式或規則導致的錯誤。
- 數據庫錯誤:與數據庫操作相關的錯誤,如查詢失敗、連接錯誤等。
2、錯誤處理中間件
錯誤處理中間件是 Express 中用于處理錯誤的特殊中間件。它有四個參數:
err
、req
、res
和next
。當在中間件或路由處理函數中調用next(err)
時,控制權會傳遞給錯誤處理中間件。
?一個簡單的代碼示范
const express = require('express');
const app = express();// 模擬一個路由處理函數,可能會拋出錯誤
app.get('/error', (req, res, next) => {const error = new Error('Something went wrong!');error.status = 500; // 設置 HTTP 狀態碼next(error); // 將錯誤傳遞給錯誤處理中間件
});// 錯誤處理中間件
app.use((err, req, res, next) => {console.error(err.stack); // 記錄錯誤堆棧res.status(err.status || 500).json({error: {message: err.message}});
});app.listen(3009, () => {console.log('Server is running on port 3009');
});
?啟動服務器,在apipost工具中進行測試。
點擊發送,得到結果
3、自定義錯誤對象
自定義錯誤對象可以幫助我們更清晰地表示特定類型的錯誤,并提供額外的上下文信息。
以下是一個自定義錯誤對象的簡單代碼示范。
const express = require('express');
const app = express();// 自定義錯誤類
class CustomError extends Error {constructor(message, status) {super(message);this.status = status;this.name = 'CustomError';}
}// 模擬路由 1:拋出自定義錯誤
app.get('/custom-error', (req, res, next) => {const error = new CustomError('Custom error occurred', 400);next(error);
});// 模擬路由 2:拋出普通錯誤
app.get('/error', (req, res, next) => {const error = new Error('Something went wrong!');error.status = 500;next(error);
});// 錯誤處理中間件
app.use((err, req, res, next) => {console.error(err.stack);res.status(err.status || 500).json({error: {message: err.message,name: err.name}});
});app.listen(3009, () => {console.log('Server is running on port 3009');
});
啟動服務,打開apipost攻擊進行測試
?
五、總結
至此,我們初步完成第一階段的所有知識學習以及練習。多動手實踐,舉一反三,希望文章的案例會對大家有所幫助。
接下來的文章,我們接著第二階段的知識學習以及代碼案例練習。第二階段的大綱如下:
第二階段:進階與應用
如果你喜歡這篇文章,請點贊收藏。
關注我,獲取前端更多使用知識。
最近業務需求多,會比較忙,但我也會抽出時間進行更新文章,敬請期待。