#node.js #fetch #buffer
Вопрос:
Я создаю два буфера из изображений и хотел бы отправить их клиенту в одном ответе с сервера узла.
Сервер:
const response1 = await fetch(imageUrls[0]);
const response2 = await fetch(imageUrls[1]);
const arrayBuffer1 = await response1.arrayBuffer();
const arrayBuffer2 = await response2.arrayBuffer();
const buffer1 = Buffer.from(arrayBuffer1, "base64");
const buffer2 = Buffer.from(arrayBuffer2, "base64");
res.setHeader("Content-Type", "application/json");
res.send(
JSON.stringify({
first: buffer1,
second: buffer2,
})
);
Клиент:
fetch(endpoint new URLSearchParams(paramsObj), {
method: "GET",
headers: {
"Content-type": "application/json",
},
})
.then((response) => {
const { first, second } = JSON.parse(response.body);
obv.blob().then((blob) => download(blob));
rev.blob().then((blob) => download(blob));
})
Проблема в том, что response.body
это все еще читаемый поток, а не анализируемая строка, как я ожидал бы получить JSON.stringify
.
Я также попытался отправить комбинированный ответ с двумя res.write()
s, но получил только первый буфер.
Следующее работает, если я отправляю только 1 буфер с сервера с res.send(buffer1)
:
.then((response) => {
response.blob().then((blob) => download(blob));
})
Комментарии:
1. В JSON нет способа выражения объекта буфера. Это не базовый тип, который поддерживает JSON. Таким образом, вам, вероятно, нужно закодировать или преобразовать буфер во что-то, что JSON знает, как представлять (массив чисел или кодированную строку). Или вам нужно отправить его как контент другого типа, чем application/json.
2. Что вы собираетесь делать с полученными изображениями? Отобразить их в
<img>
? Нарисовать их на холсте? Скачать их?3. Да, загрузите их, и получение данных с сервера предотвратит любые проблемы с CORS (исходный домен не находится под моим контролем).
Ответ №1:
Если вы хотите отправить буферы в формате JSON, вам следует рассмотреть возможность преобразования их в строки Base64, а затем отправить объект JSON в ответ, как вы уже делаете. Я не думаю, что формат JSON поддерживает буферы.
const response1 = await fetch(imageUrls[0]);
const response2 = await fetch(imageUrls[1]);
const buffer1 = convertBufferToBase64(response1);
const buffer2 = convertBufferToBase64(response2);
res.setHeader("Content-Type", "application/json");
res.send(
JSON.stringify({
first: buffer1,
second: buffer2,
})
);
Альтернативой может быть потоковая передача буфера в ответе, и в этом случае вам придется установить заголовок типа содержимого в какой-либо двоичный формат, например application/octet-stream или около того.
const response1 = await fetch(imageUrls[0]);
const arrayBuffer1 = await response1.arrayBuffer();
res.setHeader("Content-Type", "application/octet-stream");
res.send(
arrayBuffer1
);
Лично я бы просто перенаправил клиента на получение изображения самостоятельно, установив заголовок местоположения и код состояния в ответе следующим образом.
const imageUrls = ["blah", "hablo"];
res.setHeader("Location", imageUrls[0]);
res.status(301); //may also use 302 | 303 | 307 | 308
res.end();
Комментарии:
1. Спасибо, это хорошо работает со следующим кодом на клиенте:
.then((response) => response.json()).then((parsed) => { const { first, second } = parsed; downloadBase64File(first); downloadBase64File(second); });