繁体   English   中英

如何在 Next.js 中创建将 CSV 文件发送到前端的 api 路由

[英]how to create api route that will send a CSV file to the frontend in Next.js

据我所知(如果我错了,请纠正我)下载文件的流程应该是前端调用 api 路由,其他一切都在服务器上进行。

我的任务是从firestore读取并将其写入CSV文件,我用数据填充了CSV文件,现在当我尝试将其发送到前端时,只有下载后文件中的第一行包含标题姓名和电子邮件(在我的计算机上写入的文件正确地与数据一起使用)。 这是我的路线

import { NextApiHandler } from "next";
import fs from "fs";
import { stringify } from "csv-stringify";
import { firestore } from "../../firestore";
import { unstable_getServerSession } from "next-auth/next";
import { authOptions } from "./auth/[...nextauth]";

const exportFromFirestoreHandler: NextApiHandler = async (req, res) => {
  const session = await unstable_getServerSession(req, res, authOptions);

  if (!session) {
    return res.status(401).json({ message: "You must be authorized here" });
  }

  const filename = "guestlist.csv";
  const writableStream = fs.createWriteStream(filename);
  const columns = ["name", "email"];
  const stringifier = stringify({ header: true, columns });

  const querySnapshot = await firestore.collection("paprockibrzozowski").get();
  await querySnapshot.docs.forEach((entry) => {
    stringifier.write([entry.data().name, entry.data().email], "utf-8");
  });
  stringifier.pipe(writableStream);
  const csvFile = await fs.promises.readFile(
    `${process.cwd()}/${filename}`,
    "utf-8"
  );

  res.status(200).setHeader("Content-Type", "text/csv").send(csvFile);
};

export default exportFromFirestoreHandler;

因为我等待 querySnapshot 并等待 readFile 我希望文件的全部内容将被发送到前端。 你能告诉我我做错了什么吗?

谢谢

如果有人会为同样的事情而苦苦挣扎,这是@ Nelloverflowc 的答案,谢谢你让我走到这一步,hoverver 文件并不总是填充数据,起初我尝试过这样

 stringifier.on("close", async () => {
    const csvFile = fs.readFileSync(`${process.cwd()}/${filename}`, "utf-8");
    res
      .status(200)
      .setHeader("Content-Type", "text/csv")
      .setHeader("Content-Disposition", `attachment; filename=${filename}`)
      .send(csvFile);
  });
  stringifier.end();

https://csv.js.org/的 api 必须已更改,因为它现在已关闭,而不是 on.('finish'),因此读取文件同步完成了有关始终使用正确数据填充文件的工作,但随之而来的是一个错误

API resolved without sending a response for /api/export-from-db, this may result in stalled requests.

解决方案是像这样将文件转换为可读流

  try {
    const csvFile = fs.createReadStream(`${process.cwd()}/${filename}`);
    res
      .status(200)
      .setHeader("Content-Type", "text/csv")
      .setHeader("Content-Disposition", `attachment; filename=${filename}`)
      .send(csvFile);
  } catch (error) {
    res.status(400).json({ error });
  }

这是帮助我的步骤和讨论

Node.js 发送文件作为响应

forEach 上的await绝对不是你期望它做的事情,你可能也不应该一起使用 await 和 forEach

要么切换到对csv-stringify库使用 Sync API,要么按照这些方式做一些事情(假设第一个.get()实际上包含来自 Promise 的实际值):

[...]
  stringifier.pipe(writableStream);
  stringifier.on('finish', () => {
    const csvFile = await fs.promises.readFile(
       `${process.cwd()}/${filename}`,
        "utf-8"
     );
     res.status(200).setHeader("Content-Type", "text/csv").send(csvFile);
  });
  for (const entry of querySnapshot.docs) {
      stringifier.write([entry.data().name, entry.data().email], "utf-8");
  );
  stringifier.end();

[...]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM