使用 multer 和 nodejs 将图像上传到谷歌云存储时出错

Posted

技术标签:

【中文标题】使用 multer 和 nodejs 将图像上传到谷歌云存储时出错【英文标题】:Uploading images to google cloud storage with multer and nodejs getting error 【发布时间】:2021-11-03 04:58:27 【问题描述】:

== 9/9 更新问题 ===

尝试直接使用 Multer 而不像以前那样使用中间件,并使用 Postman 上传图片。

从 Nodejs,req 返回

  files: [Object: null prototype] 
    imagebackup: [ [Object] ],
    imagebanner: [ [Object] ]
  ,

但是,当我控制台 req.file 它显示“未定义”

新文件-routers.js 如下:

const express = require('express');
const multer = require('multer');
const router = express.Router();
const upload = multer(
  storage: multer.MemoryStorage,
).fields([name: "imagebackup", name: "imagebanner"]);


router.post('/file', (req, res)=>
  
  upload(req, res, (err) => 
    console.log(req) // return Files [object null]
    console.log(req.file) // return "undefined" 

    if(err) throw err;
  )
    
);

**奇怪的是,通过使用 upload.single(),一切正常。 **

==

== =====这是旧代码&无法解决===== 它返回一个错误

MulterError: Unexpected field
    at wrappedFileFilter (C:\Users\carchaw\Documents\pfx_template_generator_api\node_modules\multer\index.js:40:19)
    at Busboy.<anonymous> (C:\Users\carchaw\Documents\pfx_template_generator_api\node_modules\multer\lib\make-middleware.js:114:7)
    at Busboy.emit (node:events:379:20)

在表单提交时,我需要从不同的输入字段上传 2 张图片,在 GCS 上创建新的前缀,并将图片的名称和其他详细信息存储在 request.body 中。

从前端部分,我使用 Fetch 如下:

const getFormContianer = document.getElementById("get_form")
 async function handleForm(e) 
    e.preventDefault();
    let dataForm = new FormData(e.target)
    
   await fetch(file_api, 
        method: 'POST',    
        body: dataForm
        
    ).then((res)=>
        return res.json();
    ).then((data)=>
        console.log('api err: '+data);
    ).catch((err) =>
        console.log('api err: '+ err)
    )
    


getFormContianer.addEventListener('submit', handleForm)

index.html

<form id="get_form">
<label for="video_url">video_url</label>
<input name="video_url" type="text" id="video_url" value=""><br>
<label for="image_backup">image_backup</label>
<input name="image_backup" type="file" id="image_backup" value=""><br>
<label for="image_banner">image_banner</label>
<input name="image_banner" type="file" id="image_banner" value=""><br>
</form>
<input type="submit" id="handle_submit">

节点

multer 中间件

const util = require("util");
const multer = require("multer");

let processFile = multer(
  storage: multer.memoryStorage()
).fields([ name: "image_backup" ,  name: "image_banner" ])

let processFileMiddleware = util.promisify(processFile);
module.exports = processFileMiddleware;

处理上传

const handleUploadImages = async (req, res) =>
  try 
    await processFile(req, res);

    if (!req.file) 
      return res.status(400).send( message: "Please upload a file!" );
    

    // Create a new blob in the bucket and upload the file data.
    const blob = bucket.file(newFolderPath + req.file.originalname);
    const blobStream = blob.createWriteStream(
      resumable: false,
    );

    blobStream.on("error", (err) => 
      res.status(500).send( message: err.message );
    );

    blobStream.on("finish", async (data) => 
      // Create URL for directly file access via HTTP.
      const publicUrl = format(
        `https://storage.googleapis.com/$bucket.name/$newFolderPath/$blob.name`
      );

      try 
        // Make the file public
        await bucket.file(newFolderPath + req.file.originalname).makePublic();
       catch 
        return res.status(500).send(
          message:
            `Uploaded the file successfully: $newFolderPath + req.file.originalname, but public access is denied!`,
          url: publicUrl,
        );
      

      res.status(200).send(
        message: "Uploaded the file successfully: " + newFolderPath + req.file.originalname,
        url: publicUrl,
      );
    );

    blobStream.end(req.file.buffer);
   catch (err) 
    res.status(500).send(
      message: `Could not upload the file: $req.file.originalname. $err`,
    );
  

我确实在 index.js 上使用了 express json 和 urlencoded

const express = require('express');
const cors = require('cors'); 
const config = require('./config')
const app = express()

const templates = require('./routes/templates-routes');
const files = require('./routes/files-routes');

// Middleware
app.use(cors());
app.use(express.json());
app.use(express.urlencoded( extended: true ));  


app.use(express.static('public'))
app.use('/api', templates.routes);
app.use('/create', files.routes);


app.listen(config.port, () => 
    console.log(`Example app listening at http://localhost:$config.port`)
  )

希望能得到一些建议,谢谢!

【问题讨论】:

您能否在代码到达 fetch 语句之前在帖子中包含 FormData 的 console.log() 输出? @kvicera 如果你的意思是 console.log(dataForm) ?是这样显示的:FormData [[Prototype]]: FormData 我猜它可以直接用于新 FormData 的控制台? 能否提供您正在学习的教程的链接? @drauedo 这是链接:bezkoder.com/google-cloud-storage-nodejs-upload-file 【参考方案1】:

经过几天的尝试终于解决了这个问题。

对于前端 POST REST API,通过附加文件本身和名称来传递文件。

 function handleForm(e) 
    e.preventDefault();
    let dataForm = new FormData(e.target)
   
    dataForm.append("image_backup", document.getElementById("image_backup").files[0]);    
    dataForm.append("image_banner", document.getElementById("image_banner").files[0]);
    dataForm.append("image_banner_name", document.getElementById("image_banner").value.replace(/^.*[\\\/]/, ''));
    dataForm.append("image_backup_name", document.getElementById("image_backup").value.replace(/^.*[\\\/]/, ''));
    
   await fetch(file_api, 
        method: 'POST',    
        body: dataForm
        
    ).then((res)=>
        return res.json();
    ).then((data)=>
        console.log('api data: '+ data);
    ).catch((err) =>
        console.log('api err: '+ err)
    )
    

在 Nodejs 上

const multer = require('multer');
const upload = multer(
  storage: multer.MemoryStorage,
).fields([name: "image_backup", name: "image_banner"]);

const startCreatefiles = async(req, res, next) =>
 
  upload(req, res, (err) =>   
    
     console.log(req.body);
      console.log(req.files);
      
  )    

然后成功获取文本表单数据和文件本身。

【讨论】:

【参考方案2】:

我建议您查看他们讨论same issue 的帖子。

为了解决这个问题,他们基本上格式化了需要上传的文件。

formData.append("type_of_the_file", uploadfile);

【讨论】:

嗨~我之前确实找到了这个帖子。我确认我输入的字段名称与我在 Multer 字段中输入的名称相同,仍然出现相同的错误【参考方案3】:

body: dataForm 在哪里声明?当您尝试上传字段中未提及的字段时会出现该错误:

fields([ name: "image_backup" ,  name: "image_banner" ])

确保您的多部分表单包含这 2 个字段,仅用于上传文件。

【讨论】:

它从我在 index.html 部分中发布的表单中获取信息。使用表单提交的完整功能更新了我的问题! @carolchaw 您可以尝试将dataForm 本身作为请求主体传递吗?您不需要将其字符串化 iirc。结帐this 是的,我确实将 dataForm 作为正文直接传递。 (代码中没有使用 Json.stringify,我应该删除它以避免混淆)

以上是关于使用 multer 和 nodejs 将图像上传到谷歌云存储时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用 multer-s3 nodejs 将图像上传到亚马逊 s3

如何在nodejs中使用sharp调整图像大小然后使用multer上传

如何在nodejs中使用sharp调整图像大小然后使用multer上传

javascript 将图像上传到MongoDB - (NodeJS Express Multer && GridFsStorage)

如何使用 multer 模块将图像上传到 mongodb

将所有multer上传的文件移动到Nodejs中的新目的地