03_koa异常处理
一.全局异常处理中间件
全局异常处理的中间件需满足两个条件:
必须作为第一个中间件被注册
在next函数被调用时,使用 try-catch 即可全局捕获到异常
const catchError
= async (ctx
, next
) => {
try {
await next()
} catch(error
) {
ctx
.body
= "服务器出错了"
}
}
module
.exports
= catchError
const Koa
= require('koa')
const Router
= require('koa-router')
const catchError
= require('./exception/exception')
const app
= new Koa()
const router
= new Router()
router
.get('/api/v1/other/exception', async (ctx
, next
) => {
throw new Error()
})
app
.use(catchError
)
app
.use(router
.routes())
.use(router
.allowedMethods())
app
.listen(3000)
二.定义错误返回格式
在程序里捕捉到的error,不应该直接返回到客户端,而需要将error进行简化,返回给前端清晰明了的错误信息 我们应该返回给前端哪些信息:
HTTP Status Code: http状态码,2xx、4xx、5xx
100 “continue”101 “switching protocols”102 “processing”200 “ok”201 “created”202 “accepted”203 “non-authoritative information”204 “no content”205 “reset content”206 “partial content”207 “multi-status”208 “already reported”226 “im used”300 “multiple choices”301 “moved permanently”302 “found”303 “see other”304 “not modified”305 “use proxy”307 “temporary redirect”308 “permanent redirect”400 “bad request”401 “unauthorized”402 “payment required”403 “forbidden”404 “not found”405 “method not allowed”406 “not acceptable”407 “proxy authentication required”408 “request timeout”409 “conflict”410 “gone”411 “length required”412 “precondition failed”413 “payload too large”414 “uri too long”415 “unsupported media type”416 “range not satisfiable”417 “expectation failed”418 “I’m a teapot”422 “unprocessable entity”423 “locked”424 “failed dependency”426 “upgrade required”428 “precondition required”429 “too many requests”431 “request header fields too large”500 “internal server error”501 “not implemented”502 “bad gateway”503 “service unavailable”504 “gateway timeout”505 “http version not supported”506 “variant also negotiates”507 “insufficient storage”508 “loop detected”510 “not extended”511 “network authentication required”
message: 文字化的错误信息
errorCode: 开发者自己定义,10001、10002…
requestUrl: 当前请求的url
const Koa
= require('koa')
const Router
= require('koa-router')
const catchError
= require('./exception/exception')
const app
= new Koa()
const router
= new Router()
router
.get('/api/v1/other/exception', async (ctx
, next
) => {
const error
= new Error('服务器异常')
error
.errorCode
= 10001
error
.status
= 500
error
.requestUrl
= `${ctx.method} ${ctx.path}`
throw error
})
app
.use(catchError
)
app
.use(router
.routes())
.use(router
.allowedMethods())
app
.listen(3000)
const catchError
= async (ctx
, next
) => {
try {
await next()
} catch(error
) {
if(error
.errorCode
) {
ctx
.body
= {
code
: error
.errorCode
,
msg
: error
.message
,
request
: error
.requestUrl
}
ctx
.status
= error
.status
}
}
}
module
.exports
= catchError
三.定义HttpException异常基类
class HttpException extends Error {
constructor(msg = '服务器异常', errorCode = 10000, status = 500) {
super()
this.msg = msg
this.errorCode = errorCode
this.status = status
}
}
module.exports = HttpException
const HttpException
= require('./http-exception')
const catchError
= async (ctx
, next
) => {
try {
await next()
} catch(error
) {
if(error
instanceof HttpException) {
ctx
.body
= {
code
: error
.errorCode
,
msg
: error
.msg
,
request
: `${ctx.method} ${ctx.path}`
}
ctx
.status
= error
.status
}
}
}
module
.exports
= catchError
const Koa
= require('koa')
const Router
= require('koa-router')
const catchError
= require('./exception/exception')
const HttpException
= require('./exception/http-exception')
const app
= new Koa()
const router
= new Router()
router
.get('/api/v1/other/exception', async (ctx
, next
) => {
const error
= new HttpException()
throw error
})
app
.use(catchError
)
app
.use(router
.routes())
.use(router
.allowedMethods())
app
.listen(3000)
四.定义一系列特定异常类,继承自HttpException
const HttpException
= require('../exception/http-exception')
class ParameterException extends HttpException {
constructor(msg
, errorCode
) {
super()
this.msg
= msg
|| '参数错误'
this.errorCode
= errorCode
|| 10001
this.status
= 400
}
}
class NotFoundException extends HttpException {
constructor(msg
, errorCode
) {
super()
this.msg
= msg
|| '资源未找到'
this.errorCode
= errorCode
|| 10002
this.status
= 404
}
}
module
.exports
= {
ParameterException
,
NotFoundException
}
const requireDirectory
= require('require-directory')
const Router
= require('koa-router')
class InitManager {
static initCore(app
) {
InitManager
.app
= app
InitManager
.initExceptions()
InitManager
.initRouters()
}
static initRouters() {
let apiDirectory
= `${process.cwd()}/app/api`
requireDirectory(module
, apiDirectory
, {visit
: function(obj
) {
if(obj
instanceof Router) {
InitManager
.app
.use(obj
.routes())
.use(obj
.allowedMethods())
}
}})
}
static initExceptions() {
let errors
= require('./api-exceptions')
global
.errors
= errors
}
}
module
.exports
= InitManager
const Router
= require('koa-router')
const router
= new Router()
router
.get('/api/v1/other/exception', async (ctx
, next
) => {
const error
= new global.errors.NotFoundException()
throw error
})
module
.exports
= router
const Koa
= require('koa')
const catchError
= require('./exception/exception')
const InitManager
= require('./core/init')
const app
= new Koa()
app
.use(catchError
)
InitManager
.initCore(app
)
app
.listen(3000)
五.处理未知异常
const HttpException
= require('./http-exception')
const catchError
= async (ctx
, next
) => {
try {
await next()
} catch(error
) {
if(error
instanceof HttpException) {
ctx
.body
= {
code
: error
.errorCode
,
msg
: error
.msg
,
request
: `${ctx.method} ${ctx.path}`
}
ctx
.status
= error
.status
} else {
ctx
.body
= {
code
: 10000,
msg
: "服务器异常",
request
: `${ctx.method} ${ctx.path}`
}
}
}
}
module
.exports
= catchError