koa
koa copied to clipboard
manually close the connection after ctx.body
I have a route like this: api.put('/my/path', mdw0, body({fields:'body'}),mdw1, mdw2, controller);
The first middleware mdw0 reads some headers before the body is parsed and might decide to send an error if the size is > allowed_size or to call await next()
The problem is that the connection remains active till the end of the upload, so I don't have any advantage in using this strategy, the actual response with 413 arrives to the browser immediately if I kill the node process otherwise it remains in pending till the end.
So, how can i manually end the connection after i set ctx.status and ctx.body?
ctx.res.end()
Thanks, It was one of my first attempt. I have something like this
ctx.status=413; ctx.body=jcompose(ctx.status); ctx.res.end();
Unfortunately, the upload keeps going till the end, even if morgan prints the log out.
I even tried to throw an error: ctx.throw ('payload too big',413)
The upload keeps going till the end.
This seems to be app specific problem, or perhaps (what looks like) koa-router
. I can't reproduce this at all. Throw works as intended (and I'm pretty sure there's tests coverage for this as well).
'use strict'
const Koa = require('koa')
const app = new Koa()
app.use((ctx, next) => {
ctx.state.mwCalled = []
return next()
.catch((err) => { ctx.body = ctx.state.mwCalled })
})
app.use((ctx, next) => {
ctx.state.mwCalled.push('first')
return next()
})
app.use((ctx, next) => {
ctx.state.mwCalled.push('second')
ctx.throw('payload to big', 413)
return next()
})
app.use((ctx, next) => {
ctx.state.mwCalled.push('third')
})
app.listen()
I tried your code, I made just few changes in the middleware 2 that now looks like:
app.use((ctx, next) => {
ctx.state.mwCalled.push('second')
let contentLen = parseInt(ctx.request.header['content-length']);
if (contentLen > 10971520) {
console.log("Content-lenth too big, I throw an exception");
ctx.throw('payload to big', 413)
}
else
return next()
})
When I upload a file with size less then 10971520, I get ["first", "second", "third"] If I upload a bigger file, I see in the console "Content-lenth too big, I throw an exception" but in the browser the network status is "pending" till the end of the upload. When the whole file has been uploaded, I finally receive the output. As expected, it is just [ "first", "second"] So, it actually blocks the flow, but it does not stop the upload.
I believe this is an issue with node itself, not with koa. I remember doing the same thing before v1, but http
changed some time
Can you send a response code like 204 or 500? or ctx.res.close()
this will require investigating http
itself. if anyone wants to make a non-koa test case, that would be great!
So I'm trying my luck on this one by POSTing a large file to a native node server, e.g:
'use strict'
const http = require('http')
// edit noticed now that this was the last iteration, tried multiple "variations" :)
function handleRequest (req, res) {
if (parseInt(req.headers['content-length']) > 1375347) {
res.end('to large')
}
res.end('done in full')
}
const server = http.createServer(handleRequest)
server.listen(8000)
It seems to me that even though res.end()
is called, the socket isn't actually destroyed and there still an 100 continuation handshake. res.end()
just sets closed state and writes what's passed (i.e. user cannot write now).
If socket is manually res.destroy()
'ed (via ctx.res.destroy()
in Koa context), I think OP would get the expected result (i.e. connection dropped, don't care about the full file being sent or not - though I'm not sure about the implications of actually doing this).
I'm still new to the inner workings of http and haven't even begun debugging socket, so I might be off here.
Hello! Any updates?
I have same problem with throwing errors when large files are uploading: the connection with the client doesn't close. I tried to use @koa/multer
, koa-body
and just formidable
, the result is the same - the error occurs, then I can catch it in my errorHandler
middleware to write ctx.status
and ctx.body
, but the connection would be alive until the file compleatly loaded. With @koa/multer
I had one another problem: uploading stopped and never finished, so now I use formidable
.
Executing this code at the end of errorHandler
solves problem, but it looks like a dirty hack:
if (error instanceof SomeUploadingError()) {
// nextTick is needed to wait for ctx.body to be written in response
process.nextTick(() => {
ctx.req.destroy();
});
}
Btw, I tried to use multer
with express
. Same logic, same errors, but result is different - the connection ends immediately when an error occurs and the client receives it. @koa/multer
are using multer
, so the problem somewhere in koa
logic I guess.
Ready to provide additional information if needed.