I have a use case where I’m implementing a limited reverse proxy for a particular service to work around the fact one site enforces CORS and the service doesn’t support HTTPS. The images are small enough and I expect to have low-enough traffic I can get away with creating a single in-memory buffer and concatenating them all with Buffer.concat
when it finishes (the images are all fairly small), but this is definitely suboptimal and it’d be easier to just return the stream. Streaming would also scale better and take less memory.
My code currently looks something like this:
"use strict"
const http = require("http")
exports.handler = async (event, context) => {
const res = await once(http.get(url), "response")
const chunks = []
let size = 0
function receive(buf) {
size += buf.length
chunks.push(buf)
}
res.on("data", receive)
try {
await once(res, "end")
} finally {
res.removeListener("data", receive)
}
return {
// headers, status code, etc.
isBase64Encoded: true,
body: Buffer.concat(received, size).toString("base64"),
}
}
function once(emitter, event) {
return new Promise((resolve, reject) => {
function pass(arg) {
emitter.removeListener("error", fail)
resolve(arg)
}
function fail(arg) {
emitter.removeListener(event, fail)
reject(arg)
}
emitter.once(event, pass)
emitter.once("error", fail)
})
}
Ideally, I’d use a rewrite rule and instructing Netlify to explicitly not cache the returned result as the backend server in question returns a random image that changes on each request, with headers explicitly stating to not cache the response. But since this functionality doesn’t exist, it’s much easier to just write a function than file a very specific feature request for that. And unlike OP, I do at least have the option of keeping the full response in memory for a short period of time.
If I could return a stream from the body knowing it’d get implicitly .pipe
d to the response, I’d do this instead, removing about 50% of the code in my function’s handler:
exports.handler = async (event, context) => {
const res = await once(http.get(url), "response")
return {
// headers, status code, etc.
body: res,
}
}