Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

图片上传报错 TypeError: source.on is not a function #39

Closed
tzwm opened this issue Mar 19, 2023 · 5 comments
Closed

图片上传报错 TypeError: source.on is not a function #39

tzwm opened this issue Mar 19, 2023 · 5 comments
Labels
good first issue Good for newcomers

Comments

@tzwm
Copy link

tzwm commented Mar 19, 2023

写了个简单的图片批量上传脚本, 有比较奇怪的错误,想要求助一下。
client 其他的消息发送指令都正常使用没问题,就是图片上传这个有点异常。

@larksuiteoapi/node-sdk 版本 1.12.0

[error]: [
  [
    TypeError: source.on is not a function
        at Function.DelayedStream.create (/Users/tzwm/projects/MTRPG-AI/node_modules/delayed-stream/lib/delayed_stream.js:33:10)
        at FormData.CombinedStream.append (/Users/tzwm/projects/MTRPG-AI/node_modules/combined-stream/lib/combined_stream.js:45:37)
        at FormData.append (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/form-data/lib/form_data.js:75:3)
        at build (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/helpers/toFormData.js:63:16)
        at each (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/helpers/toFormData.js:58:9)
        at Object.forEach (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/utils.js:276:12)
        at build (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/helpers/toFormData.js:40:13)
        at toFormData (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/helpers/toFormData.js:67:3)
        at Object.transformRequest (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/defaults/index.js:80:14)
        at transform (/Users/tzwm/projects/MTRPG-AI/node_modules/@larksuiteoapi/node-sdk/node_modules/axios/lib/core/transformData.js:18:15)
  ]
]
fs.readdir(directory, (err, files) => {
  // 过滤出所有图片文件
  const imageFiles = files.filter(file => {
    const extension = file.split('.').pop()?.toLowerCase();
    return extension === 'jpg' || extension === 'jpeg' || extension === 'png' || extension === 'gif';
  });

  // 输出所有图片文件的文件名
  console.log('Image files in directory:');
  imageFiles.forEach(file => {
    console.log(file);
    const buffer = fs.readFileSync(directory + "/" + file);
    //console.log(buffer);
    client.im.image.create({
      "data": {
        "image_type": "message",
        "image": buffer,
      }
    }).then(res => {
      console.log(res);
    }).catch(err => console.log("errorrrrrrrr", err))
  });
});
@tzwm
Copy link
Author

tzwm commented Mar 19, 2023

呃另外我不太会 JS,这个上传脚本是 ChatGPT 帮忙写的,但我大致看了下没啥毛病,出错的地方在 larkclient API 调用上,其他逻辑看起来没问题。

@mazhe-nerd
Copy link
Collaborator

厉害呀同学,ChatGPT可以的。
我试了一下正常的调用链路是可以的:
image

可以先试试发送单个图片看看?排除下文件本身的原因

@mazhe-nerd mazhe-nerd closed this as not planned Won't fix, can't repro, duplicate, stale Mar 27, 2023
@DevinDon
Copy link

DevinDon commented Apr 1, 2023

报错详情

LTS 版本18.15.0 的 Node.js 调用 im.image.create 方法会有问题,报错基本一致;切到版本 16.20.0 就没有问题。

[
  [
    TypeError: source.on is not a function
        at DelayedStream.create (/xxx/node_modules/.pnpm/[email protected]/node_modules/delayed-stream/lib/delayed_stream.js:33:10)
        at CombinedStream.append (/xxx/node_modules/.pnpm/[email protected]/node_modules/combined-stream/lib/combined_stream.js:45:37)
        at FormData.append (/xxx/node_modules/.pnpm/[email protected]/node_modules/form-data/lib/form_data.js:75:3)
        at build (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/helpers/toFormData.js:63:16)
        at each (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/helpers/toFormData.js:58:9)
        at Object.forEach (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/utils.js:276:12)
        at build (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/helpers/toFormData.js:40:13)
        at toFormData (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/helpers/toFormData.js:67:3)
        at Object.transformRequest (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/defaults/index.js:80:14)
        at transform (/xxx/node_modules/.pnpm/[email protected]/node_modules/axios/lib/core/transformData.js:18:15)
  ]
]

溯源 - 直接原因

在 Node 16 里,CombinedStream.append 调用传进来的数据是一个 Buffer

神奇的判断逻辑

但是在 Node 18 里,CombinedStream.append 调用传进来的数据是一个 Blob

image

CombinedStream.isStreamLike 这个方法显然没有考虑 Blob 这种情况,显而易见的就把 Blob 当作 Stream 交给了 DelayedStream.create 处理,结果调用了不存在的 on 方法,报错。

image

接下来找找根本原因。

溯源 - 根本原因

在 Nodejs 16 中,追踪整个调用栈上的参数类型,在 build 之前都是 Uint8Arraybuild 之后都是 Buffer,看起来没什么问题。

image

那问题应该与 build 方法有关,我们检查下 build 的逻辑。

image

convertValue 中有转换类型的逻辑,在 formData.append 入参中,类型已经从 Uint8Array 转为了 Buffer,我们检查下逻辑:

image

哦吼,看到问题了,Nodejs 16 中没有 Blob 这种类型,所以用的是 Buffer 来承载数据;但是 Nodejs 18 中有了 Blob 就会优先使用 Blob 类型;刚好碰到一个类型校验不严谨的(笑),就搞了个 bug。

image

解决方案

在聊解决方案之前,让我先吐槽下这个类型断言逻辑,这种逻辑是哪个天才想出来的,不是 Buffer 就是 Stream?这不是妥妥的瞧不起 null 和 undefined 一大家子吗?

image

我扔个 global 进去都能搞崩(笑)。

正确的处理逻辑应当使用 instanceof ReadStream 或者 instanceof Stream 方式,起码逻辑应该是:我认出来你是 Stream,你才是 Stream,否则我就不支持。

有两个方案解决:

  1. 降级 Nodejs 到不支持 Blob 特性的低版本,或者在全局干掉 Blob 对象(有风险)
  2. 私有仓库发个 [email protected] 版本的同名包给替换掉,这玩意已经好几年没更新了,别指望作者能修问题

上述建议仅供参考,如有问题欢迎指出。

@mazhe-nerd
Copy link
Collaborator

感谢同学提供思路,我这边看下尽快修复

@mazhe-nerd mazhe-nerd added the good first issue Good for newcomers label Apr 6, 2023
@mazhe-nerd mazhe-nerd pinned this issue Apr 17, 2023
@mazhe-nerd
Copy link
Collaborator

mazhe-nerd commented Jun 6, 2023

1.17.1版本以上可以使用stream代替buffer,1.17.1以下版本需要对image字段ts-ignore一下:

 const file = fs.createReadStream('your url');
  client.im.image.create({
    data: {
      image_type: 'message',
      image: file
    }
  }).then(res => {
    console.log(res);
  }).catch(e => {
    console.log(e);
  });

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

3 participants