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

Express.js + AWS S3异步问题:POST提前返回200致下载异常

解决Express+AWS S3中POST返回时PDF未生成的问题

你的问题根源在于formHandler函数虽标记为async,但内部使用了S3回调式API,导致异步操作未被正确等待。当await formHandler(formData)执行时,s3.getObject的回调还未完成PDF填充与上传,函数就提前返回,POST接口先返回200,而S3中的文件尚未生成。

1. 重构formHandler模块,改用Promise式S3操作

将回调式的S3操作改为Promise形式,确保所有异步步骤都被await:

require("dotenv").config();
const AWS = require("aws-sdk");
const { PDFDocument } = require("pdf-lib");

const formHandler = async (formData) => {
  try {
    const s3 = new AWS.S3();
    const downloadParams = {
      Bucket: process.env.BUCKET,
      Key: "forms/rawForm.pdf",
    };

    // 改用Promise形式获取S3对象,替代回调
    const form = await s3.getObject(downloadParams).promise();
    const pdfFormBuffer = form.Body;

    // 等待PDF填充与上传完成
    await fillOutPDFForm(pdfFormBuffer, formData, s3);
  } catch (err) {
    console.error("表单处理出错:", err);
    throw err; // 抛出错误让上层接口捕获
  }
};

const fillOutPDFForm = async (pdfFormBuffer, formData, s3) => {
  const pdfDoc = await PDFDocument.load(pdfFormBuffer);
  const form = pdfDoc.getForm();
  // 此处填写表单填充业务逻辑
  // 示例:form.getTextField('username').setText(formData.username);

  const modifiedPdfBuffer = await pdfDoc.save();
  await saveModifiedPDFToS3(modifiedPdfBuffer, s3);
};

const saveModifiedPDFToS3 = async (modifiedPdfBuffer, s3) => {
  const bufferData = Buffer.from(modifiedPdfBuffer);
  const uploadParams = {
    Bucket: process.env.BUCKET,
    Key: "output/preparedForm.pdf",
    Body: bufferData,
  };

  await s3.upload(uploadParams).promise();
};

module.exports = formHandler;

2. 优化Express POST接口的错误处理

确保formHandler出错时,接口返回错误状态码,避免静默失败:

// FORM PREPARATION
app.post("/form", async (req, res) => {
  try {
    const formData = req.body; // req.body无需await,express.json()已完成解析
    await formHandler(formData);
    res.status(200).json({
      status: "PDF created.", // 修正原代码中的"satus"拼写错误
    });
  } catch (err) {
    console.error("POST接口出错:", err);
    res.status(500).json({ error: "PDF生成失败,请重试" });
  }
});

额外优化建议

  • 避免文件覆盖:当前所有用户生成的PDF共用同一个preparedForm.pdf,会导致后续用户覆盖之前的文件。建议根据请求ID、时间戳或用户信息生成唯一文件名(如output/preparedForm-${Date.now()}.pdf),并在POST返回时将文件名传给前端,下载接口根据文件名获取对应文件。
  • 完善下载接口错误提示:针对文件不存在的情况返回更友好的提示:
s3Stream.on("error", (err) => {
  if (err.code === 'NoSuchKey') {
    res.status(404).send("文件尚未生成,请稍后重试");
  } else {
    console.error("Error downloading file from S3:", err);
    res.status(500).send("Error downloading file");
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 11:02:46