通过 POST 请求上传文件时 NodeJS 获取失败(object2 不可迭代)

Har*_*ent 17 javascript rest node.js fetch-api

我正在尝试使用 NodeJS 中的本机 fetch 上传文件(在节点 17.5 中添加,请参阅https://nodejs.org/ko/blog/release/v17.5.0/)。

但是,我不断收到以下错误 -

TypeError: fetch failed
at Object.processResponse (node:internal/deps/undici/undici:5536:34)
at node:internal/deps/undici/undici:5858:42
at node:internal/process/task_queues:140:7
at AsyncResource.runInAsyncScope (node:async_hooks:202:9)
at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
cause: TypeError: object2 is not iterable
at action (node:internal/deps/undici/undici:1660:39)
at action.next (<anonymous>)
at Object.pull (node:internal/deps/undici/undici:1708:52)
at ensureIsPromise (node:internal/webstreams/util:172:19)
at readableStreamDefaultControllerCallPullIfNeeded
node:internal/webstreams/readablestream:1884:5)
at node:internal/webstreams/readablestream:1974:7
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

      
Run Code Online (Sandbox Code Playgroud)

我使用以下代码来创建并提交表单响应 -

TypeError: fetch failed
at Object.processResponse (node:internal/deps/undici/undici:5536:34)
at node:internal/deps/undici/undici:5858:42
at node:internal/process/task_queues:140:7
at AsyncResource.runInAsyncScope (node:async_hooks:202:9)
at AsyncResource.runMicrotask (node:internal/process/task_queues:137:8)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
cause: TypeError: object2 is not iterable
at action (node:internal/deps/undici/undici:1660:39)
at action.next (<anonymous>)
at Object.pull (node:internal/deps/undici/undici:1708:52)
at ensureIsPromise (node:internal/webstreams/util:172:19)
at readableStreamDefaultControllerCallPullIfNeeded
node:internal/webstreams/readablestream:1884:5)
at node:internal/webstreams/readablestream:1974:7
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

      
Run Code Online (Sandbox Code Playgroud)

Mos*_*aei 11

表单数据包的问题:

Node.js 无法解析 formData 结构,因此它会抛出object2 is not iterable

另一方面,悲伤的故事是formData将不再维护,您可能已经注意到,距离上一个版本发布已经过去了两年。于是他们正式宣布formData将被归档: 为formData的棺材上敲下最后的钉子

这会是弃用的时候吗?form-data 已经有一段时间没有更新了,它仍然缺少一些应该根据规范提供的方法。由于与规范兼容的 FormData 不一致,node-fetch@3 stopp 建议 ppl 使用 form-data,并建议 ppl 使用内置 FormData 或支持迭代所有字段并支持 Blob/File 的规范:ed formdata 填充


解决方案

1.使用form-data包:

简而言之,我们需要以某种方式将表单数据流转换为 Node.js 流。这可以借助一些流方法来完成,如下所示:

流.转换:

通过stream.TransformNode.js 流中的类并传递表单数据实例,我们可以使用内置的 fetch API 发送请求。

来自 Node.js 文档:

变换流是双工流,其中输出以某种方式与输入相关。与所有 Duplex 流一样,Transform 流同时实现 Readable 和 Writable 接口。

所以我们可以这样实现:

import { Transform } from 'stream';

// rest of code

const tr = new Transform({
  transform(chunk, encoding, callback) {
    callback(null, chunk);
  },
});
formData.pipe(tr);

const request = new Request(url, {
  method: 'POST',
  headers: form_headers,
  duplex: 'half',
  body: tr
})

let raw_response = await fetch(request);
Run Code Online (Sandbox Code Playgroud)

流.PassThrough

我们可以简单地使用stream.PassThrough

import { PassThrough } from 'stream';

// rest of code

const pt = new PassThrough()
formData.pipe(pt);

const request = new Request(url, {
  method: 'POST',
  headers: form_headers,
  duplex: 'half',
  body: pt
})

let raw_response = await fetch(request);
Run Code Online (Sandbox Code Playgroud)

重要提示:如果您没有通过duplex: 'half',您将收到此错误:

duplex option is required when sending a body
Run Code Online (Sandbox Code Playgroud)

2.使用内置的表单数据

目前,Node.js 核心处理fetch的部分名为undici

幸运的是,您不需要使用任何第三方模块来处理任何表单数据,因为undici已经实现了它并且现在是 Node.js 核心的一部分。

遗憾的是,使用undici流媒体的一部分并不容易和直接。但是,您仍然可以实现它。

duplex option is required when sending a body
Run Code Online (Sandbox Code Playgroud)

PS:您可能需要阅读本期,了解有关编码的部分。