[英]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 });
}
这是帮助我的步骤和讨论
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.