node/js 使用站点地图库生成的站点地图已损坏

generated sitemaps are corrupted using sitemap library for node/js

我正在使用名为 sitemap 的库从 运行 期间构建的对象数组生成文件。我的目标是将这些生成的站点地图上传到 S3 存储桶。 到目前为止,该函数托管在 AWS lambda 上并将生成的文件正确上传到存储桶。

我的问题是,生成的站点地图已损坏。当我在本地 运行 函数时,它们可以正确生成,没有任何问题。

这是我的处理程序:

module.exports.handler = async () => {
  try {
    console.log("inside handler....");
    await clearGeneratedSitemapsFromTmpDir();
    const sms = new SitemapAndIndexStream({
      limit: 10000,
      getSitemapStream: (i) => {
        const sitemapStream = new SitemapStream({
          lastmodDateOnly: true,
        });

        const linkPath = `/sitemap-${i + 1}.xml`;
        const writePath = `/tmp/${linkPath}`;
        sitemapStream.pipe(createWriteStream(resolve(writePath)));
        return [new URL(linkPath, hostName).toString(), sitemapStream];
      },
    });

    const data = await generateSiteMap();
    sms.pipe(createWriteStream(resolve("/tmp/sitemap-index.xml")));
    // data.forEach((item) => sms.write(item));
    Readable.from(data).pipe(sms);
    sms.end();
    await uploadToS3();
    await clearGeneratedSitemapsFromTmpDir();
  } catch (error) {
    console.log(" ~ file: index.js ~ line 228 ~ exec ~ error", error);
    Sentry.captureException(error);
  }
};

data 变量有一个大约 11k 项的数组,因此根据上面的代码,除了站点地图索引外,还会生成两个站点地图文件(第一个 10k,其余为第二个站点地图)列出两个生成的站点地图。

这是我的 uploadToS3 函数:

const uploadToS3 = async () => {
  try {
    console.log("uploading to s3....");
    const files = await getGeneratedXmlFilesNames();
    for (let i = 0; i < files.length; i += 1) {
      const file = files[i];
      const filePath = `/tmp/${file}`;
      // const stream = createReadStream(resolve(filePath));
      const fileRead = await readFileAsync(filePath, { encoding: "utf-8" });
      const params = {
        Body: fileRead,
        Key: `${file}`,
        ACL: "public-read",
        ContentType: "application/xml",
        ContentDisposition: "inline",
      };

      // const result = await s3Client.upload(params).promise();
      const result = await s3Client.putObject(params).promise();
      console.log(
        " ~ file: index.js ~ line 228 ~ uploadToS3 ~ result",
        result
      );
    }
  } catch (error) {
    console.log("uploadToS3 => error", error);
    // Sentry.captureException(error);
  }
};

下面是在上传到 S3 后从 lambda 的 /tmp 目录中清除生成的文件的函数:

const clearGeneratedSitemapsFromTmpDir = async () => {
  try {
    console.log("cleaning up....");
    const readLocalTempDirDir = await readDirAsync("/tmp");
    const xmlFiles = readLocalTempDirDir.filter((file) =>
      file.includes(".xml")
    );
    for (const file of xmlFiles) {
      await unlinkAsync(`/tmp/${file}`);
      console.log("deleting file....");
    }
  } catch (error) {
    console.log(
      " ~ file: index.js ~ line 207 ~ clearGeneratedSitemapsFromTmpDir ~ error",
      error
    );
  }
};

我的直觉是这个问题与流有关,因为我还没有完全理解它们。 非常感谢此处的任何帮助。

旁注:我尝试在上传前休眠 10 秒,但这也没有用。

作为解决方法,我这样做了:

const data = await generateSiteMap();
const logger = createWriteStream(resolve("/tmp/all-urls.json.txt"), {
  flags: "a",
});
data.forEach((el) => {
  logger.write(JSON.stringify(el));
  logger.write("\n");
});
logger.end();

const stream = lineSeparatedURLsToSitemapOptions(
  createReadStream(resolve("/tmp/all-urls.json.txt"))
)
  .pipe(sms)
  .pipe(createWriteStream(resolve("/tmp/sitemap-index.xml")));

await new Promise((fulfill) => stream.on("finish", fulfill));
await uploadToS3();
await clearGeneratedSitemapsFromTmpDir();

如果有人回答正确,问题将保持开放状态。