如何使用 formdata 将图像文件发送到 React/Next js api?

Posted

技术标签:

【中文标题】如何使用 formdata 将图像文件发送到 React/Next js api?【英文标题】:How to send an image file using formdata to React/Next js api? 【发布时间】:2021-02-04 23:25:09 【问题描述】:

我正在尝试将文件发送到下一个 js 应用程序中的 api。图片将上传到 cloudinary:

函数调用api是:

  async uploadButtonClicked(imageUpload) 
      const formData = new FormData();
      //formData.append('test', "testing");
      formData.append('postPic', imageUpload.files[0]);
      const res = await fetch('/api/hello', 
        method: 'POST',
        headers: 
          'Content-Type': 'multipart/form-data',
          'Accept': 'application/json'
        ,
        body: formData,
      )

console.log(imageUpload.files[0]) 在前端给了我下面的值,看起来不错。

在api中,

export default (upload.single('postPic'), async (req, res) => 
  console.log(req.body)

上面是我使用时的undefined

export const config = 
  api: 
    bodyParser: false,
  ,
;

当我删除 bodyParser 设置(bodyParser 为 true)时,数据会以流的形式出现,对上传没有用处。我收到如下所示的上传错误:

如果正文以以下格式到达 api,Cloudinary 将上传:

应该进行哪些更改才能使正文(基本上是一个图像文件)以正确的格式到达 api,如上所示?

我认为这个问题也可以问为:为什么使用bodyParser: falsereq.body undefined

【问题讨论】:

您的 API 在哪里实现(Next.js 的 API 路由或其他项目/框架)? @nghiaht 它在 nextjs api 路由中。谢谢 【参考方案1】:

我遇到了同样的错误,但 Formidable 对我有用。尝试先将图像放入表单数据中。

来自客户:

export const uploadImage = async (image) => 

    const formData = new FormData();
    formData.append('image', image);
    const response = await axios.post('/api/v1/image', formData);
    return response.data;

以下是服务器 API:/api/v1/image

import formidable from 'formidable';


export const config = 
  api: 
    bodyParser: false,
  ,


export default async (req, res) => 
  const form = new formidable.IncomingForm();
  form.uploadDir = "./";
  form.keepExtensions = true;
  form.parse(req, (err, fields, files) => 
    console.log(err, fields, files);
  );
;

【讨论】:

谢谢。我已经将图像放入表单数据中 - formData.append('postPic', imageUpload.files[0]);。您能否解释一下在这种情况下强大的功能以及为什么要使用它? 在这种情况下,它用于读取表单数据并提供文件。我得到的东西类似于你想要实现的东西(客户端 -> NextJS -> Express Server -> Cloudinary 告诉我你的进展情况。【参考方案2】:

如果您要上传到 Cloudinary,为什么要尝试将文件从客户端发送到 nextjs api? 您可以直接上传到 Cloudinary。

使用像 react-uploady 这样的库。就这么简单:

import React from "react";
import Uploady from "@rpldy/uploady";
import UploadButton from "@rpldy/upload-button";

const CLOUD_NAME = "<your-cloud-name>";
const UPLOAD_PRESET = "<your-upload-preset>";

const App = () => (<Uploady
    destination= 
        url: `https://api.cloudinary.com/v1_1/$CLOUD_NAME/upload`,
        params: 
            upload_preset: UPLOAD_PRESET,
        
    >
    <UploadButton/>
</Uploady>);

【讨论】:

也许他想隐藏使用第三服务的秘密 一般来说是的。对于 Cloudinary,不需要隐藏这些参数。在生产中应该做的是使用signed uploads - 意思是在服务器端签署上传数据 @nghiaht - 我认为最好进行签名上传隐藏 api 值。最后,我确实最终直接使用带有 POST 的 cloudinary api url,但它需要上传预设和未签名的上传。 这是一个非常有趣的问题。我正在尝试处理 Next.js 的 API 路由中的多部分表单数据,他们说这是核心 Node.js http 请求,我尝试使用 formidable 解析但失败了。如果我能解决它,我会发布一个答案 @Kal 请不要在生产代码中进行未签名的上传。它将允许任何人使用详细信息上传到您的云。签名上传是生产环境中的最佳方式。如果您需要这方面的帮助,请告诉我【参考方案3】:

这对我有用

import cloudinary from 'cloudinary';
import formidable from 'formidable';

cloudinary.config( 
  cloud_name: '', 
  api_key: '', 
  api_secret: '' 
);

export const config = 
  api: 
    bodyParser: false,
  ,


export default async (req, res) => 
  const form = new formidable.IncomingForm();
  form.uploadDir = "./";
  form.keepExtensions = true;
  await form.parse(req, (err, fields, files) => 
    cloudinary.v2.uploader.upload(files.image.path, function(error, result) 
      res.status(200).json(
        success: true,
        data: result.secure_url
      )
    );
  );

【讨论】:

虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。

以上是关于如何使用 formdata 将图像文件发送到 React/Next js api?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 FormData 发送文件数组?

我可以在javascript中将数组附加到“formdata”吗?

将图像的源(src)添加到 formData 并通过 http post call 将其发布到后端

如何在 Flask 中接受通过 ajax 发送的 FormData?

为什么我的文件数组没有附加到FormData?

使用 jQuery.ajax 发送 multipart/formdata