-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide a way to flush compression stream on demand #3599
Comments
Interesting. I was not aware that this is possible using compressed streams. |
@mtharrison How would an api user access the |
The only way I think we can support something like this is with a new response api that lets you define blocks: const handler = (request, h) => {
return h.response().block('This\n').block('is\n').block('being\n').block('streamed!');
}; And then if compression is involved, we flush it after writing each block. However, since we do not write to the response stream until the handler is done, the only way this works well is by crafting a response stream and returning that, and doing some of the handler work inside the stream data read events. In which case, this API is useless and we need to expose the flush action as something we hand over the readable stream at pipe time. Hmm. |
I have been playing around with this and was able to get it to work by exposing the compressor on the response (last line in this snippet of let compressor = null;
if (encoding &&
length !== 0 &&
response._isPayloadSupported()) {
delete response.headers['content-length'];
response._header('content-encoding', encoding);
compressor = (encoding === 'gzip' ? Zlib.createGzip() : Zlib.createDeflate());
}
response.compressor = compressor; // added this line I'm sure you can think of a less hacky way to do this but it then allows me to do const handler = (request, reply) => {
const stream = new Stream.PassThrough();
reply(null, stream).type('text/html').code(200);
stream.write('<html><head><script src="https://unpkg.com/react@15.3.1/dist/react.min.js"></script>');
setTimeout(() => {
// `compressor` won't be available till next tick
request.response.compressor.flush()
setTimeout(() => {
stream.write('</head><body>hello</body></html>');
stream.end();
}, 2000);
});
} |
Got this working in hapi 17.8.5 with the new setCompressor changes added in c49b9c8 handler(request, h) {
class ResponseStream extends Stream.PassThrough {
setCompressor(compressor) {
this._compressor = compressor;
}
}
const stream = new ResponseStream()
stream.write('<!DOCTYPE html><html><head></head><body>hello')
setTimeout(() => {
stream._compressor.flush()
setTimeout(() => {
stream.write(' world</body></html>')
stream.end()
}, 1000)
})
return h.response(stream)
.type('text/html')
} So awesome! Thanks @hueniverse! |
It's useful to be able to tell the payload compression stream to flush its content, for example when wanting the browser to render the HTML document
<head>
and download the associated resources while you're still generating or writing the document body.Express's compression middleware achieves this by offering a
res.flush()
method. I think something similar would be useful in hapi for better control of streaming compressed content.Streaming compressed payload with hapi
Streaming compressed payload with express+compression
The text was updated successfully, but these errors were encountered: