0

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

例如,假设一个包含文本输入和文件输入的多部分表单,并且将所有具有相同名称的文件输入分组是不切实际的,例如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 也没关系。

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

   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每次接收到新流时都会更新,并且只会在第一个图像被完全接收(顺序)之后发生,但如果我等待上游数组完成,我也会收到超时错误。

有什么解决方法吗?

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

4

1 回答 1

0

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

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()
}

我认为船长不应该这样做,并强迫这种黑客行为,所以也许我错过了一些东西,如果我错过了,请告诉我。

于 2017-04-22T02:00:24.973 回答