Section-5 多種方案實現(xiàn)錯誤處理機制

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)堆棧全部都列出來了

使用koa-json-error后的錯誤處理

然而在生成環(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ù)器

開發(fā)環(huán)境報錯信息

執(zhí)行 npm run build,啟動生產(chǎn)環(huán)境服務(wù)器

生產(chǎn)環(huán)境報錯信息


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ā)者進行錯誤處理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末修噪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子路媚,更是在濱河造成了極大的恐慌黄琼,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件整慎,死亡現(xiàn)場離奇詭異脏款,居然都是意外死亡,警方通過查閱死者的電腦和手機院领,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來够吩,“玉大人比然,你說我怎么就攤上這事≈苎” “怎么了强法?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵万俗,是天一觀的道長。 經(jīng)常有香客問我饮怯,道長闰歪,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任蓖墅,我火速辦了婚禮库倘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘论矾。我一直安慰自己教翩,他們只是感情好,可當我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布贪壳。 她就那樣靜靜地躺著饱亿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪闰靴。 梳的紋絲不亂的頭發(fā)上彪笼,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音蚂且,去河邊找鬼配猫。 笑死,一個胖子當著我的面吹牛膘掰,可吹牛的內(nèi)容都是我干的章姓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼识埋,長吁一口氣:“原來是場噩夢啊……” “哼凡伊!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窒舟,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤系忙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惠豺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體银还,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年洁墙,在試婚紗的時候發(fā)現(xiàn)自己被綠了蛹疯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡热监,死狀恐怖捺弦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤列吼,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布幽崩,位于F島的核電站,受9級特大地震影響寞钥,放射性物質(zhì)發(fā)生泄漏慌申。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一理郑、第九天 我趴在偏房一處隱蔽的房頂上張望蹄溉。 院中可真熱鬧,春花似錦香浩、人聲如沸类缤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽餐弱。三九已至,卻和暖如春囱晴,著一層夾襖步出監(jiān)牢的瞬間膏蚓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工畸写, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留驮瞧,地道東北人。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓枯芬,卻偏偏與公主長得像论笔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子千所,可洞房花燭夜當晚...
    茶點故事閱讀 43,490評論 2 348