Потоковая передача запросов узлов в облако с метаданными файлов

Я использую koa для создания веб-приложения и хочу разрешить пользователям загружать в него файлы. Файлы должны передаваться в облако, но я бы не хотел сохранять файл локально.

Проблема в том, что мне нужны некоторые метаданные файла, прежде чем я перенаправлю поток загрузки в доступный для записи поток. Я хочу иметь MIME-тип и при желании прикрепить другие данные, такие как исходное имя файла и т. д.

Я попытался отправить двоичные данные с заголовком «content-type» запроса, установленным в тип файла, но я хотел бы, чтобы запрос имел тип контента application/octet-stream, чтобы я мог знать в бэкэнде, как обрабатывать запрос.

Я где-то читал, что лучшим вариантом было бы использовать multipart/form-data, но я не уверен, как структурировать запрос и как анализировать метаданные, чтобы уведомить облако, прежде чем я передам его потоку записи.

Вот код, который я сейчас использую. По сути, он просто передает запрос как есть, и я использую заголовок запроса, чтобы узнать тип файла:

module.exports = async ctx => {
  // Generate a random id that will be part of the filename.
  const id = pushid();
  // Get the content type from the header.
  const contentType = ctx.header['content-type'];
  // Get the extension for the file from the content type
  const ext = contentType.split('/').pop();

  // This is the configuration for the upload stream to the cloud.
  const uploadConfig = {
    // I must specify a content type, or know the file extension.
    contentType

    // there is some other stuff here but its not relevant.
  };

  // Create a upload stream for the cloud storage.
  const uploadStream = bucket
    .file(`assets/${id}/original.${ext}`)
    .createWriteStream(uploadConfig);

  // Here is what took me hours to get to work... dev life is hard
  ctx.req.pipe(uploadStream);

  // return a promise so Koa doesn't shut down the request before its finished uploading.
  return new Promise((resolve, reject) =>
    uploadStream.on('finish', resolve).on('error', reject)
  );
};

Пожалуйста, предположим, что я мало знаю о протоколах загрузки и управлении потоками.


person Samuel E.    schedule 08.07.2018    source источник


Ответы (1)


Итак, после долгих поисков я обнаружил, что есть парсер, который работает с потоками под названием busboy. Он довольно прост в использовании, но перед тем, как перейти к коду, я настоятельно рекомендую всем, кто имеет дело с multipart/form-data запросами, посетить прочитать эту статью.

Вот как я это решил:

const Busboy = require('busboy');

module.exports = async ctx => {
  // Init busboy with the headers of the "raw" request.
    const busboy = new Busboy({ headers: ctx.req.headers });

    busboy.on('file', (fieldname, stream, filename, encoding, contentType) => {
        const id = pushid();
        const ext = path.extname(filename);
        const uploadStream = bucket
            .file(`assets/${id}/original${ext}`)
            .createWriteStream({
                contentType,
                resumable: false,
                metadata: {
                    cacheControl: 'public, max-age=3600'
                }
            });

        stream.pipe(uploadStream);
    });

  // Pipe the request to busboy.
    ctx.req.pipe(busboy);

  // return a promise that resolves to whatever you want
    ctx.body = await new Promise(resolve => {
        busboy.on('finish', () => {
            resolve('done');
        });
    });
};
person Samuel E.    schedule 09.07.2018