Sometimes you may want to wrap your middleware in try - catch statement.
If one uses ctx.assert -method inside a try statement, which sets the ctx.status, one might come across with counter intuitive behavior.
For example:
(ctx, next) => {
try {
ctx.assert(false, '400', 'this is bad')
}
catch (error) {
console.log(ctx.status) // 400
ctx.body = 'whoops, the status will be 200 after setting me'
console.log(ctx.status) // 200
}
}
However, this one works as expected:
(ctx, next) => {
try {
ctx.assert(false, '400', 'this is bad')
}
catch (error) {
ctx.status = ctx.status // This sets the _explicitStatus to true
console.log(ctx.status) // 400
ctx.body = 'now works'
console.log(ctx.status) // 400 as expected
}
}
I guess there is nothing wrong in this behavior. ctx.assert does not set ctx.status. It throws Error object with status key set to the value you've specified. After that it's as per the user to decide what to do with it. So error throwing and status handling are kind of decoupled.
Here's koa context default error handler source code:
https://github.com/koajs/koa/blob/841844ee2fd0cf91478b5ed8d2f401e8b97eb4a2/lib/context.js#L143-L144
Then it uses error status to set context status:
https://github.com/koajs/koa/blob/841844ee2fd0cf91478b5ed8d2f401e8b97eb4a2/lib/context.js#L149
Btw assert test checks error object, not context.status:
https://github.com/koajs/koa/blob/841844ee2fd0cf91478b5ed8d2f401e8b97eb4a2/test/context/assert.js#L15
If you raise the error without handling it in try/catch you'll get the correct response code.
Here's a source example of 3 cases:
const
CODE = 400,
MSG = "this is bad";
const handlerDefault = (ctx) => {
ctx.assert(false, CODE, MSG);
};
const handlerCustom = (ctx) => {
try
{
ctx.assert(false, CODE, MSG);
}
catch (err)
{
console.log(`Hit custom error handler, err.status: ${err.status}`);
}
};
const handlerCustomCode = (ctx) => {
try
{
ctx.assert(false, CODE, MSG);
}
catch (err)
{
ctx.status = err.status || 500;
console.log(`Hit custom error handler, ctx.status set to err.status: ${ctx.status}`);
}
};
You'll get:
400 as koa propagates it in default error handler404 as a default HTTP response code (or 200 if body is set)400 as context status was set explicitlyFull example source code here.
It's also worth checking documentation.
@garcia556, thanks for your extensive answer!
Most helpful comment
I guess there is nothing wrong in this behavior.
ctx.assertdoes not setctx.status. It throwsErrorobject withstatuskey set to the value you've specified. After that it's as per the user to decide what to do with it. So error throwing and status handling are kind of decoupled.Here's koa
contextdefault error handler source code:https://github.com/koajs/koa/blob/841844ee2fd0cf91478b5ed8d2f401e8b97eb4a2/lib/context.js#L143-L144
Then it uses error
statusto set contextstatus:https://github.com/koajs/koa/blob/841844ee2fd0cf91478b5ed8d2f401e8b97eb4a2/lib/context.js#L149
Btw
asserttest checkserrorobject, notcontext.status:https://github.com/koajs/koa/blob/841844ee2fd0cf91478b5ed8d2f401e8b97eb4a2/test/context/assert.js#L15
If you raise the error without handling it in try/catch you'll get the correct response code.
Here's a source example of 3 cases:
You'll get:
400as koa propagates it in default error handler404as a default HTTP response code (or200ifbodyis set)400as contextstatuswas set explicitlyFull example source code here.
It's also worth checking documentation.