You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Amazon S3下载文档上传为Xero发票附件触发TypeError错误求助

问题根源

你调用Xero接口时传入的body参数类型不符合要求:

  • 你通过S3 getObject 加 .promise() 获取到的file.Body是Buffer类型
  • Xero的createInvoiceAttachmentByFileName接口要求body参数为**可读流(Readable Stream)**类型,SDK内部会调用流的.on()方法监听数据事件,Buffer对象不存在该方法,因此抛出TypeError: body.on is not a function错误。

解决方案

有两种可行的修改方式,任选其一即可:

方案1:将获取到的Buffer转为可读流(修改量最小)

在调用Xero上传接口前,把S3返回的Buffer转为可读流即可,Node.js 12及以上版本可直接用内置stream模块的Readable.from方法实现:
首先引入依赖:

const { Readable } = require('stream');

修改主流程中调用sendAttachmentToInvoice的传参:

await xeroService.sendAttachmentToInvoice(
      integration.tenant.id,
      sendInvoicesResponse.body.invoices[0].invoiceID,
      document.name,
      // 把Buffer转为可读流传入
      Readable.from(downloadedDocument.data),
      downloadedDocument.mimetype,
    );

方案2:直接从S3获取可读流(性能更优,适合大文件)

无需把整个文件加载到内存转为Buffer,直接返回S3的可读流给Xero接口,修改AWS的downloadDocument方法:

module.exports.downloadDocument = async (key) => {
  try {
    const getParams = {
      Bucket: config.aws.documentsBucket,
      Key: key,
    };
    // 先获取文件元信息拿到mimetype,再创建可读流
    const headData = await s3.headObject(getParams).promise();
    const fileStream = s3.getObject(getParams).createReadStream();
    return {
      data: fileStream,
      mimetype: headData.ContentType,
    };
  } catch (error) {
    const message = error.message;
    logger.error(`download document from AWS fail | message=${message}`);
    throw new Error(message);
  }
};

这种方式避免了大文件场景下的内存占用过高问题,更推荐使用。

额外修复点

你原代码的所有catch分支中存在变量未定义的问题:message没有声明就直接使用,需要补上const message = error.message;,否则会抛出额外的引用错误。

内容的提问来源于stack exchange,提问作者siri

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 01:51:03