如何使用 Node.js 通过 API 上传图片?

这个问题已经被多次提出,但到目前为止,没有任何解决方案对我有效。

我正在使用 Node.js 通过 API 为帖子上传图片。

创建帖子没有问题,但图片无法上传。

我将图片(一个 PNG 文件)转换为二进制字符串。

然后,我发送一个 application/json 请求,在请求头中包含 API 凭证,负载如下:

{
   type: "composer",
   synchronous: true,
   file: `${binary_string}`
}

我尝试了按照 API 文档建议使用 file 作为字段名,也尝试了按照 论坛中的另一个帖子建议 使用 files[]

使用 file 时,我收到 422 错误,提示:

undefined method `tempfile' for #<String:0x00007fdfeba2b1d8>

使用 files[] 时,我收到 422 错误,提示“Unprocessable Entity”(无法处理的实体)。

除了按照文档使用 application/json 外,我还尝试了像 Web 界面和 这位发帖人 那样使用 multipart/form-data

对于 form-data 请求,我是这样做的:

 const form = new FormData();
 form.append("type", "composer");
 form.append("synchronous", "true");
 form.append("files[]", this.stringToBinary(file.data!), {
      contentType: file.mimetype,
 });

http.post("/uploads.json", form.getBuffer(), {
  headers: form.getHeaders(),
 }) // 凭证会被添加

使用这种方式时,无论使用 file 还是 files[],我都收到 422 错误,提示:

undefined method `tempfile' for #<String:0x00007fdfeba2b1d8>

有人能帮忙吗?

我这样实现了它:

import Axios from "axios";
import FormData from "form-data";
import fs from "fs";
const http = Axios.create({
  baseURL: "https://forum.zeebe.io",
  headers: {
    "Api-Key":
      "...",
    "Api-Username": "...",
    "Content-Type": "application/json",
    Accept: "application/json",
  },
});
http.interceptors.request.use((config) => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
});

const filename = "/Users/sitapati/Desktop/process.png";
const file = fs.readFileSync(filename);
const form = new FormData();
form.append("files[]", file, {
  filename,
});

http
  .post("/uploads.json", form, {
    params: {
      type: "composer",
      synchronous: true,
    },
  })
  .then(({ data }) => {
    console.info("Discourse 的响应", JSON.stringify(data, null, 2));
    return {
      url: data.url,
    };
  })
  .catch((e) => {
    console.error(
      "上传文件到 Discourse 时出错",
      JSON.stringify(e, null, 2)
    );
    throw e;
  });

它也可以用于从远程 URL 获取的文件,获取方式如下:

Axios.get(file.slackUrl, {
   responseType: "arraybuffer",
   headers: { Authorization: "Bearer " + this.slackToken },
})

关键在于:responseType: "arraybuffer"