NodeJS 服务器端 - 文件预期 UploadFile,接收:<class 'str'>

NodeJS server side - file Expected UploadFile, received: <class 'str'>

提问人:aaa 提问时间:11/10/2022 最后编辑:aaa 更新时间:5/18/2023 访问量:1348

问:

从 NodeJs 服务器端上传文件时遇到问题,发现 100 个帖子和搜索,但没有任何效果,将不胜感激。

应用程序的结构

  1. Front App - React Admin 框架接收文件,我在 base64 中编码要发送到 API 的图像内容

  2. 后端 - NestJS App - 在 API 中接收 base64 镜像

  3. 从我的后端 API 需要将文件发送到外部后端(Python API)进行上传 - 这是问题所在

请看下面我的代码,JS中的文件有问题

我尝试了几种方法,但都以相同的错误告终

1 解决方案

  • 在缓冲区中转换 base64 图像并发送到外部后端上传文件
  • 也尝试通过 cleanImageBuffer,但没有更改
import axios from 'axios';
import FormData from 'form-data';

export async function upload(
  fileBase64: string,
  filename: string
): Promise<any> {

  const buffer = Buffer.from(fileBase64, 'base64')
  const extension = fileBase64.substring(fileBase64.indexOf('/') + 1, fileBase64.indexOf(";base64"))
  const cleanBase64 = fileBase64.replace(/^data:image\/png;base64,/, '')
  const cleanImageBuffer = Buffer.from(cleanBase64, 'base64')

  const formData = new FormData();
  // have tried to pass as well cleanImageBuffer but no changes
  formData.append('file', buffer);
  formData.append('fileName', filename + '.' + extension);
  formData.append('namespace', 'test');
  
  return await axios
    .post('external_api_url', JSON.stringify(formData), {
      headers: {
        Authorization: `Bearer token`,
        ContentType: 'multipart/form-data'
      }
    })
    .then((response) => {
      console.log('response = ' + JSON.stringify(response))
    })

结果 1 解决方案

{
    "status": "error",
    "error": {
        "code": "bad_request",
        "message": "file Expected UploadFile, received: <class 'str'>"
    }
}

2 解决方案

  • 从 base64 接收到的图像保存在我的磁盘上
  • 创建流并发送图像后
export async function upload (
  fileBase64: string,
  filename: string
): Promise<any> {

  const extension = fileBase64.substring(fileBase64.indexOf('/') + 1, fileBase64.indexOf(";base64"))
  const cleanBase64 = fileBase64.replace(/^data:image\/png;base64,/, '')

  const TMP_UPLOAD_PATH = '/tmp'

  if (!fs.existsSync(TMP_UPLOAD_PATH)) {
    fs.mkdirSync(TMP_UPLOAD_PATH);
  }

  fs.writeFile(TMP_UPLOAD_PATH + '/' + filename + '.' + extension, cleanBase64, 'base64', function(err) {
    console.log(err);
  })

  const fileStream = fs.createReadStream(TMP_UPLOAD_PATH + '/' + filename + '.' + extension)

  const formData = new FormData();
  formData.append('file', fileStream, filename + '.' + extension);
  formData.append('fileName', filename + '.' + extension);
  formData.append('namespace', 'test');

  return await axios
    .post('external_api_url', formData, {
      headers: {
        Authorization: `Bearer token`,
        ContentType: 'multipart/form-data'
      }
    })
    .then((response) => {
      console.log('response = ' + JSON.stringify(response))
    })
}

结果 2 解决方案

{
    "status": "error",
    "error": {
        "code": "bad_request",
        "message": "file Expected UploadFile, received: <class 'str'>"
    }
}

以相同结果结束的其他解决方案

  • 尝试从 node-fetch 使用 fetch - 相同的结果
  • 发现有些人的 Axios 版本已经过时并且遇到了这个问题,我已经安装了最新的 Axios 版本 1.1.3,但结果相同

我需要的最佳方案

  • 从 base64 图像接收到
  • 在缓冲区中转换并将文件发送到外部 Python API,以避免将文件保存在本地磁盘上

将不胜感激任何帮助

下面是一个可以工作但不能使用 JS 的 python 示例(JS 不起作用)

import requests

url = "http://127.0.0.1:8000/external_api"

payload={'namespace': 'test'}
files=[
  ('file',('lbl-pic.png',open('/local/path/lbl-pic.png','rb'),'image/png'))
]
headers = {
  'Authorization': 'Bearer token'
}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

print(response.text)
node.js 文件上传 axios 服务器端 图片上传

评论

0赞 Geshode 11/10/2022
该错误是来自 Python API 还是来自Node.js?
0赞 aaa 11/10/2022
当我通过 axios 发布时,@Geshode错误来自 Python API,但我粘贴了一个有效的 python 代码示例

答:

1赞 yagger 11/10/2022 #1

只是一个建议:

  1. 首先看看你是否可以使它与常规的 HTML 文件输入一起工作(不要使 Base64 复杂化),如此处所述 https://stackoverflow.com/a/70824288/2347084
  2. 如果 (1) 有效,则尝试将 base64 转换为 File 对象,如此处建议 https://stackoverflow.com/a/47497249/2347084
  3. 组合 (2) 和 (1)

评论

0赞 aaa 11/14/2022
很奇怪的node-fetch,最终只出现类型错误,比如node_fetch_1.File不是一个函数,node_fetch_1,File不是一个构造函数,在服务器上用node-fetch无法解决这个错误,node-fetch使用的任何内容都以类型错误结束,取Base64镜像说只允许protocvols
0赞 aaa 11/19/2022
这将起作用并且是正确的,FormData 的问题
0赞 aaa 11/19/2022 #2

我想发布我的解决方案,因为正如我在互联网上看到的那样,每个人都有问题FormDatanodejs

  1. 我用来发送用于上传文件的缓冲区axios
  2. 问题是 和 特别是 ,它不会添加标头,任何版本的 Axios 都不会这样做axiosFormDataContent-Length
  3. python API 已必需Content-Length

如果此标头在 python API 中成为可选的,则代码开始工作

解决方案是,如果有人有类似的问题

  • Axios 在使用时不添加(找不到任何有效的 Axios 版本)Content-LengthFormData
  • 如果您使用缓冲区而没有将文件放在本地磁盘上,则会因为以下原因而出现问题Content-Length
  • 如果您在本地拥有文件,而不是使用模块 FS,您可以读取文件并添加所有标头和 Content-Length

在 axios GitHub 问题上说这个错误在最新的 axios 中得到了修复,但在我的情况下仍然不起作用

下面是使用 buffer 的代码,在第三个 API 中不需要 Content-Length

    function upload (image: {imageBase64: string, fileName: string}) {
      const { imageBase64, fileName } = image;
      const cleanBase64 = imageBase64.substr(imageBase64.indexOf(',') + 1);
      // buffer should be clean base64
      const buffer = Buffer.from(cleanBase64, 'base64');
    
      const formData = new FormData();
      // filename as option is required, otherwise will not work, will say that received file is string and UploadFile
      formData.append('file', buffer, { filename: fileName });
    
      return client
        .post('url', formData, {
          headers: {
            ...formData.getHeaders(),
          },
        })
        .then((response) => response.data)
        .catch((error) => {
          return {
            status: 'error',
            error,
          };
        });
    }