Lesson-1 錯誤處理簡介
什么是錯誤處理?
- 編程語言或計算機硬件里的一種機制
- 處理軟件或信息系統(tǒng)中出現(xiàn)的異常狀況
異常狀況有哪些稻薇?
- 運行時錯誤体斩,都返回500(語法正確,但是運行時候發(fā)生錯誤)
- 邏輯錯誤颖低,如找不到(404)、先決條件失敾】尽(412)忱屑、無法處理的實體(參數(shù)格式不對,422)等
為什么要用錯誤處理暇昂?
- 防止程序掛掉
- 告訴用戶錯誤信息
- 便于開發(fā)者調(diào)試
Lesson-2 Koa 自帶的錯誤處理
操作步驟
- 制造 404莺戒、412、500 三種錯誤
- 了解 Koa 自帶的錯誤處理做了什么
制造 404急波、412从铲、500 三種錯誤
- 請求地址
http://localhost:3000/users123
,狀態(tài)返回404 - 請求地址
http://localhost:3000/users/1
澄暮,狀態(tài)返回412名段,因為默認db只有一條數(shù)據(jù)
findById (ctx) {
if (+ctx.params.id >= db.length) {
// ctx.body = '先決條件失斱逖铩:id 大于數(shù)組條件長度';
// ctx.status = 412;
// return;
ctx.throw(412, '先決條件失敗:id 大于數(shù)組條件長度'); // 等價于上面三句話
}
ctx.body = db[+ctx.params.id];
}
- 請求地址
http://localhost:3000/users
伸辟,狀態(tài)返回500麻惶,因為語法正確,但是發(fā)生了程序錯誤
find (ctx) {
a.b; // a 未定義信夫,undefined去獲取屬性b
ctx.body = db;
}
Lesson-3 自己編寫錯誤處理中間件
操作步驟
- 自己編寫錯誤處理中間件
- 制造 404窃蹋、412、500 三種錯誤
自定義錯誤處理中間件
該中間件只需要寫在所有中間件前面静稻,然后捕獲next中間件警没,利用冒泡便可以捕獲到所有的異常。捕獲異常跟javascript一樣振湾,使用try/catch進行捕獲處理杀迹。根據(jù)RESTful風格,我們使用 json 將異常吐出來恰梢。這里面我們怎么知道err有什么屬性可以獲确鹉稀?通過前面打斷點的方式嵌言,來查看捕獲到的 err 存在什么字段信息嗅回,便可以直接制造一個我們需要的異常報錯信息了
// index.js
const Koa = require('koa');
const bodyparser = require('koa-bodyparser');
const app = new Koa(); // 實例化koa
const routes = require('./routes');
// 錯誤處理中間件
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
// 如果沒捕獲到狀態(tài)碼,證明是服務(wù)器內(nèi)部錯誤
ctx.status = err.status || err.statusCode || 500;
ctx.body = {
message: err.message
}
}
});
// 啟動路由
app.use(bodyparser());
routes(app);
app.listen(3000, () => {
console.log(`start server...`);
});
驗證的截圖這里就放了摧茴,有一點需要說的是绵载,404是不會進入異常捕獲里面的,如果真的需要對404進行捕獲苛白,只能通過獲取ctx.status === 404來吐出錯誤信息了娃豹,比如像下面這樣
// 錯誤處理中間件
app.use(async (ctx, next) => {
try {
await next();
// 捕獲不到異常,但狀態(tài)碼為404
if (ctx.status === 404) {
ctx.body = {
message: '頁面找不到'
}
}
} catch (err) {
// 如果沒捕獲到狀態(tài)碼购裙,證明是服務(wù)器內(nèi)部錯誤
ctx.status = err.status || err.statusCode || 500;
ctx.body = {
message: err.message
}
}
});
Lesson-4 使用 koa-json-error 進行錯誤處理
操作步驟
- 安裝 koa-json-error
- 使用 koa-json-error 的默認配置處理錯誤
- 修改配置使其在生產(chǎn)環(huán)境下禁用錯誤堆棧的返回
安裝 koa-json-error
執(zhí)行 npm i koa-json-error -S
進行安裝懂版,這個插件 npm 上的描述是顯示錯誤處理堆棧,有興趣的同學自己閱讀一下 koa-json-error NPM
使用 koa-json-error 的默認配置處理錯誤
聲明并加入全局當中
const error = require('koa-json-error');
app.use(error());
這個時候可以看到躏率,不僅出現(xiàn)了我們定義的錯誤message躯畴,還把錯誤名稱錯誤類型已經(jīng)堆棧全部都列出來了
然而在生成環(huán)境中,把錯誤堆棧也返回出來實際是不安全的薇芝,所以我們需要更改默認配置蓬抄,使其在生產(chǎn)環(huán)境中不暴露堆棧信息
修改配置使其在生產(chǎn)環(huán)境下禁用錯誤堆棧的返回
由于我們需要在 package.json 中,命令行語句里設(shè)置環(huán)境變量夯到,所以這里需要安裝一個插件嚷缭,來讓 window 和 OS X 都認識命令行當中的 NODE_ENV=production
語句,否則 windows 需要額外處理
執(zhí)行 npm i cross-env -S
安裝插件
package.js中新增一條啟動命令 "build": "cross-env NODE_ENV=production node app"
安裝完成后,我們需要修改koa-json-error的配置
// index.js
app.use(error({
// 后置的修改返回格式
postFormat: (err, {stack, ...rest}) => process.env.NODE_ENV === 'production' ? rest : {stack, ...rest}
}));
防止有的同學es6不熟悉阅爽,這句看著有點懵路幸,我寫個es5的
app.use(error({
// postFormat接受一個函數(shù),第一個為原始錯誤优床,第二個為新的格式化錯誤
postFormat: function (err, obj) {
if (process.env.NODE_ENV === 'production') {
delete obj.stack
return obj;
}
return obj;
}
}));
執(zhí)行 npm start
劝赔,啟動開發(fā)環(huán)境服務(wù)器
執(zhí)行 npm run build
,啟動生產(chǎn)環(huán)境服務(wù)器
Lesson-5 使用 koa-parameter 校驗參數(shù)
操作步驟
- 安裝 koa-parameter
- 使用 koa-parameter 校驗參數(shù)
- 制造 422 錯誤來測試校驗結(jié)果
安裝 koa-parameter
執(zhí)行 npm i koa-parameter -S
安裝插件胆敞,并全局加入
// index.js
const parameter = require('koa-parameter');
app.use(parameter(app));
使用 koa-parameter 校驗參數(shù)
其實在搜索這個插件的時候着帽,發(fā)現(xiàn)這個插件github上star 25…而且還不在官方推薦里面,但只是想驗證功能移层,能湊合用先就行仍翰,有興趣的同學可以自己看一下 koa社區(qū),挑選更加合適的插件
// controller/users.js
const db = [{name: '李雷'}];
class UsersCtl {
find (ctx) {
a.b;
ctx.body = db;
}
findById (ctx) {
if (+ctx.params.id >= db.length) {
ctx.throw(412, '先決條件失敼刍啊:id 大于數(shù)組條件長度'); // 等價于上面三句話
}
ctx.body = db[+ctx.params.id];
}
create (ctx) {
ctx.verifyParams({
name: {
type: 'string',
required: true
},
age: {
type: 'number',
required: false
}
});
db.push(ctx.request.body);
ctx.body = ctx.request.body;
}
update (ctx) {
if (+ctx.params.id >= db.length) {
ctx.throw(412, '先決條件失斢杞琛:id 大于數(shù)組條件長度'); // 等價于上面三句話
}
ctx.verifyParams({
name: {
type: 'string',
required: true
},
age: {
type: 'number',
required: false
}
});
db[+ctx.params.id] = ctx.request.body;
ctx.body = ctx.request.body;
}
delete (ctx) {
if (+ctx.params.id >= db.length) {
ctx.throw(412, '先決條件失敗:id 大于數(shù)組條件長度'); // 等價于上面三句話
}
db.splice(+ctx.params.id, 1);
ctx.status = 204; // 沒有內(nèi)容频蛔,但是成功了
}
}
module.exports = new UsersCtl();
上面涉及ctx.request.body的都加上了相同的驗證灵迫,如果驗證失敗,將返回422與詳細的錯誤信息
制造 422 錯誤來測試校驗結(jié)果
上圖晦溪,age為非必傳瀑粥,類型為數(shù)值類型,但傳了字符串類型三圆,所以出現(xiàn)驗證失敗狞换,圖中也可以看到相關(guān)的錯誤參數(shù),錯誤信息舟肉,方便開發(fā)者進行錯誤處理