Отправка более одного буфера в одном ответе с узлом

#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); });