0

我使用 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)
  );
};

请假设我对上传协议和管理流不太了解。

4

1 回答 1

0

好的,经过大量搜索后,我发现有一个解析器可以处理名为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');
        });
    });
};
于 2018-07-09T07:47:54.533 回答