【问题标题】:Why is my function called twice in storage.single?为什么我的函数在 storage.single 中被调用两次?
【发布时间】:2020-02-10 05:13:40
【问题描述】:

我不知道为什么,但我的函数在 storage.single 中被调用了两次。

app.post("/upload-file", async (req, res, next) => {
    try {
        export const inMemoryStorage = (opts = {}) => {
          return multer({ storage: multer.memoryStorage(), ...defaultOpts, 
          ...opts })
         }

        const storage = inMemoryStorage();
        storage.single('file')(req, res, () => {
         console.log(req.file) // in my last update
         console.log('called') // this is returned two times
         return this.uploadService.uploadFile(req)
          })
        } catch (err) {
           next(err);
        }
     });
}

如果您有解决方案,谢谢。我只想让我的函数被调用一次。

---- 新编辑----

所以我的uploadService是这样的:

  async uploadFile(req) {

    const b2 = new B2({
      applicationKeyId: 'private1',
      applicationKey: 'private2'
    })

    const upload = await b2.getUploadUrl({ bucketId: 'my-private-key' })

    const myfile = await b2.uploadFile({
      uploadUrl: upload.data.uploadUrl,
      uploadAuthToken: upload.data.authorizationToken,
      fileName: getFilename(req.file),
      data: req.file.buffer,
      onUploadProgress: (event) => null
    })

    console.log(myfile) // it works

    return myfile

  }

所以我的上传工作正常了,我可以看到我的 console.log。所以在我的数据库中,比如第一次上传后的 15 秒,我的方法发送了另一个文件,并且我的 console.log 返回了两次对象

--------- 最后更新 ----------

我注意到一些东西,我不知道为什么,但是当我的文件大于 50mb 时。我的函数被调用了 2 次。在 50mb 以下,一切正常,我只发送一次文件

如您所见,我添加了 console.log(req.file)。结果是:

{
  fieldname: 'file',
  originalname: 'myMovie.mp4',
  encoding: '7bit',
  mimetype: 'video/mp4',
  buffer: <Buffer 1a 45 df a3 01 00 00 00 00 00 00 23 42 86 81 01 42 f7 81 01 42 f2 81 04 42 f3 81 08 42 82 88 6d 61 74 72 6f 73 6b 61 42 87 81 04 42 85 81 02 18 53 80 ... 107390076 more bytes>,
  size: 107390126
}
{
  fieldname: 'file',
  originalname: 'myMovie.mp4',
  encoding: '7bit',
  mimetype: 'video/mp4',
  buffer: <Buffer 1a 45 df a3 01 00 00 00 00 00 00 23 42 86 81 01 42 f7 81 01 42 f2 81 04 42 f3 81 08 42 82 88 6d 61 74 72 6f 73 6b 61 42 87 81 04 42 85 81 02 18 53 80 ... 107390076 more bytes>,
  size: 107390126
}

所以我的两个req.file是一样的

【问题讨论】:

  • 你能发布完整的代码吗?例如 - this.uploadService 是什么?
  • 您可能必须像每个 JavaScript 用户一样使用分号。它可能会自行修复,前提是您在理论上执行const storage = inMemoryStorage()storage.single ...
  • 我进行了更新以向您展示我的uploadService。而且我不认为这是我的分号,因为它在两行。但我添加了一个只是为了确定

标签: node.js multer


【解决方案1】:

我想我在您更新的代码示例中看到了问题。您没有在 upload-file 路由处理程序中将响应发送回客户端,这会导致浏览器重新发送请求。

修改处理程序如下

app.post("/upload-file", async (req, res, next) => {
    try {
        export const inMemoryStorage = (opts = {}) => {
          return multer({ storage: multer.memoryStorage(), ...defaultOpts, 
          ...opts })
         }

        const storage = inMemoryStorage();
        storage.single('file')(req, res, () => {
         console.log(req.file) // in my last update
         console.log('called') // this is returned two times
            await this.uploadService.uploadFile(req);
            res.sendStatus(200); // or equivalent
          })
        } catch (err) {
           next(err);
        }
     });
}

【讨论】:

  • 非常感谢您的帮助,您找到了解决方案!
【解决方案2】:

随着调试消息called 尝试添加以下内容。

console.log(new Error().stack); 

这将帮助您确定冗余/重复呼叫的来源。

【讨论】:

  • 感谢您的回复,但我在 console.log 中没有看到任何可以帮助我的信息。一切正常
【解决方案3】:

首先,uploadFile 是一个异步函数,所以 storage.single 代码应该是这样的

storage.single('file')(req, res, async () => {
    console.log('called')
    return await this.uploadService.uploadFile(req)
})

另外,如果回调给你发回错误怎么办?

storage.single('file')(req, res, async (err) => {
    if (err) {
        // handle err
    }
    console.log('called')
    return await this.uploadService.uploadFile(req)
})

现在,我不确定你是如何在 api 中使用它的。

根据我之前处理文件上传的方式,

function fileParser(req, res, opts = {}) {
    return new Promise((resolve, reject) => {
        multer({ storage: multer.memoryStorage(), ...defaultOpts, ...opts })
        .single("file")(req, res, (err) => {
            if (err) {
               return reject(err);
            }
            return resolve();
        });
    });
}

async function fetchAndUploadFile(req, res, opts = {}) {
    await fileParser(req, res, opts);
    await uploadService.uploadFile(req);
}

// usage in api route 

app.post("/your-route", async (req, res, next) => {
    try {
        await fetchAndUploadFile(req, res);
        // other api logic & return response
    } catch (err) {
        next(err);
    }
});

试试这个,如果有帮助,请告诉我。另外,您使用的是 express 还是其他一些框架,如羽毛? (问因为我在使用羽毛框架时看到过类似的查询)

【讨论】:

  • 感谢您的回复。我尝试与您的代码完全相同,但遇到了同样的问题。但是我注意到一些东西,我不知道为什么,但是当我的文件大于 50mb 时。我的函数被调用了 2 次。我只是在我的后端使用 express
  • 很有趣。你能确认在这种情况下 API 没有被调用两次吗?我认为情况可能并非如此,但最好检查一下。也许如果文件大小大于某个大小,前端会将其划分为多个块并为每个块调用 API。不确定,但您可以检查。
  • 另外,如果可能的话,我会建议使用签名 URL 来上传文件。这样,您将减轻 API 服务器的压力。
  • 您是否将此上传服务放在快递应用程序后面?您如何以及何时看到两次日志消息。即你如何生产它?通过浏览器上传文件吗?如果它位于 express 应用程序后面,可以显示端点实现?
  • 感谢您的回复@jeeves 所以这只是一条路线,而不是快递中的应用程序。我只是使用等待来获取我的数据。我的文件是从浏览器 (chrome) 上传的,对于 50mb 以下的文件,一切正常,这很奇怪。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-31
  • 1970-01-01
  • 2013-01-12
  • 2021-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多