使用 skipper (sails.js) 处理中间件中具有不同未知输入字段名称的文件

Handle files in middleware with different unknown input field names with skipper (sails.js)

我正在尝试从提交的表单上传文件,该表单包含来自不同输入名称的多个图像文件。

例如,假设一个包含文本输入和文件输入的多部分表单,将所有文件输入分组为同名是不切实际的,例如 images[]

<form ...>
 some text inputs...
 <input type='file' name='logo'/>
 <input type='file' name='image-1'/>
 <input type='file' name='image-2'/>
</form>

我想创建一个 express/sails 中间件来处理上传,这样我就可以直接在我的控制器上访问它们。

如果我这样做(假设 req.file() 上的上传方法得到保证)

   async function(req, res, next){
      const maxTimeToBuffer = 9500
      const dirname = '/some-upload-path'
      const uploads = [
        await req.file('logo').upload(dirname, maxTimeToBuffer) 
        await req.file('image-1').upload(dirname, maxTimeToBuffer)
        await req.file('image-2').upload(dirname, maxTimeToBuffer)
      ]
      // attaching the uploads to the request body ...
      next()
  }

这将引发错误: EMAXBUFFER: An Upstream (images-1) timed out before it was plugged into a receiver. It was still unused after waiting 9500ms. You can configure this timeout by changing themaxTimeToBufferoption.

如果我将 maxTimeToBuffer 增加到 30000 甚至在 skipper 模块本身上也没关系。

由于无论如何尝试以顺序方式处理每个文件都会引发错误,只要我知道输入字段名称,就可以并行处理它们。

   async function(req, res, next){
      const maxTimeToBuffer = 9500
      const dirname = '/some-upload-path'
      const uploads = await [
        req.file('logo').upload(dirname, maxTimeToBuffer) 
        req.file('image-1').upload(dirname, maxTimeToBuffer)
        req.file('image-2').upload(dirname, maxTimeToBuffer)
      ]
      // attaching the uploads to the request body ...
      next()
  }

现在的问题是,我如何在不事先知道输入字段的情况下在最后一个片段上实现相同的目的。像这样

async function(req, res, next){
     const maxTimeToBuffer = 9500
     const dirname = '/some-upload-path'
     const uploads = await req._fileparser.upstreams
     // attaching the uploads to the request body ...
     next()
}

问题是 req._fileparser.upstreams 每次收到新流时都会更新,这只会在第一个图像完全接收(顺序)后发生,但是如果我等待上游数组完成我也会出现超时错误。

有什么解决方法吗?

我知道有很多东西需要消化,如果您需要进一步说明,请告诉我。 任何想法表示赞赏

好的,经过多次用头撞墙后我想到了这个。 我们开始 运行 流而不等待它们,每次添加新流时我们通过调用上传 运行 它,然后我们每隔 100 毫秒检查一次是否设置了 parser/form由船长关闭,当这是真的时,我们可以安全地等待所有流,最后我们解决了承诺,或者如果超时在我们拒绝之前触发。我已经简化了我的代码,因为我的代码做了很多额外的解析,我希望它能帮助其他人。

async function(req, res, next){
     const maxTimeToBuffer = 9500
     const dirname = '/some-upload-path'
     const uploads = await new Promise((resolve, reject)=> {
       const TIMEOUT = 20000
       const {upstreams} = req._fileparser
       const tasks = _.map(upstreams, (stream)=> stream.upload(dirname, maxTimeToBuffer))
       // We proxy the original push method, to push to our task list every time a new stream is added
       upstreams.push = (stream)=> {
         tasks.push(stream.upload(dirname, maxTimeToBuffer))
         Array.prototype.push.call(upstreams, stream)
       }
       const startTime = (new Date()).getTime()
       const intervalId = setInterval(async function(){
           if(req._fileparser.closed){
              clearInterval(intervalId)
              fileObjects = await tasks
              resolve(fileObjects)
            }
            else if((new Date()).getTime() - startTime > TIMEOUT){
               clearInterval(intervalId)
               reject(new Error('Timeout triggered before form closed'))
              , 100)    
            }
     })
     // attaching the uploads to the request body ...
     next()
}

我认为船长不应该这样做,并强迫这种黑客行为,所以也许我遗漏了什么,如果遗漏了,请告诉我。