用快递发回 CSV

Sending CSV back with express

我是从 JSON 导出 CSV 的新手...我非常接近这个...但我不知道如何将 CSV 从我的快递服务器发送回客户端。

用户选择要导出的客户,然后点击导出按钮...我希望将 CSV 文件发回。

我在服务器上将 JSON 数据转换为 CSV,如何将此文件发送回客户端?

这是我到目前为止的快速路线 -

    router.post('/SaveCSV', (req, res) => {

    const csv = JSONToCSV(req.body, { fields: ["Customer Name", "Business Name", "Customer Email", "Customer ID", "School ID", "Student Count", "Admin Count", "Courses Count" ]})

    
    
})

我已经尝试了res.send、res.send文件和res.attachment..有什么指导吗?

更新***

    router.post('/SaveCSV', (req, res) => {

    const csv = JSONToCSV(req.body, { fields: ["Customer Name", "Business Name", "Customer Email", "Customer ID", "School ID", "Student Count", "Admin Count", "Courses Count" ]})

    res.attachment('CustomerData.csv').send(csv)
    
})

这是我在客户端上的提取调用 --

const saveCsv = async (customers) => {
    const token = await getAccessTokenSilently();
    try {
        const response = await fetch('/api/SaveCSV', {
            method: 'POST',
            headers: {
                Authorization: `Bearer ${token}`,
                "content-type": 'application/json; Charset=UTF-8'
            },
            body: JSON.stringify(customers)
        })
        const responseData = await response.json()
        console.log(responseData)
    } catch (error) {
        console.log(error)
    }
}

JSONtoCSV可能会从JSON生成CSV格式的字符串。

从这个字符串中,您有两个选择。

  1. 将字符串发送到文本文档中,然后 res.sendFile 该文件。

    可以这样做。

    我建议使用 this package,尽管您可以使用 vanilla。只需创建文件并将字符串写入其中,然后通过 res.sendFile.

    发送
    const csv = new ObjectsToCsv(csvdata);
    
    await csv.toDisk("./data.csv");
    
    res.sendFile("./data.csv");
    
  2. 将字符串作为 JSON 发送,然后在前端将其解析为下载。这是最常见的方法。

    这可以如下所示完成:

    // Parse it into CSV with a frontend CSV library.
    
    // Then, create a hidden element and automatically download the file.
    var hiddenElement = document.createElement('a');
    hiddenElement.href = 'data:text/csv;charset=utf-8,' + encodeURI(csv);
    hiddenElement.target = '_blank';
    hiddenElement.download = 'exported.csv';
    hiddenElement.click();
    

    Source

在服务器端,您可以 send 返回 CSV 数据。默认情况下,内容类型 text/html 随附 - 最好使用正确的类型 text/csv 发送它。这可以通过先使用 res.type('text/csv') 来完成。

现在,如果您不将浏览器导航到您的端点而是在您的前端代码中以编程方式使用下载,那么这是否有必要是有争议的,但是:将其标记为“下载”(这不应该显示但实际上保存到文件中),您可以使用 res.attachment()。如果您指定文件名,它还会在 header 中发送该文件名,但还会根据扩展名自动设置内容类型。所以你可以使用 res.attachment('customers.csv').send(csv) 例如。如果浏览器导航到您的 URL,它会将 CSV 视为名称为 customers.csv.

的文件下载
router.post('/SaveCSV', (req, res) => {
    const csv = JSONToCSV(req.body, { fields: ["Customer Name", "Business Name", "Customer Email", "Customer ID", "School ID", "Student Count", "Admin Count", "Courses Count" ]})
    
    res.attachment('customers.csv').send(csv)
})

在客户端,您可以使用 response.blob() 将原始响应 body 作为 blob 获取,然后您可以让用户下载该 blob。有关如何完成的更多解释,您可以在线研究(有很多相关资源)。 here (which was also linked in a comment to this Stack Overflow answer) 是一个自动获取正确文件名并适用于旧版浏览器的完整示例 - 请注意,您需要 text/csv 而不是 application/pdf 或从中读取内容类型响应。

让我来 post 一个功能较少的简化示例:

const blob = await response.blob()
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = 'customers.csv'
link.click()
setTimeout(() => URL.revokeObjectURL(link.href), 0)

但是让我们考虑一下。根据您显示的代码,您所有的服务器代码所做的就是从前端获取数据,将其填充到 CSV 中并发回。我会说,你根本不需要服务器!您可以在前端代码中完成所有事情!

const saveCsv = (customers) => {
  const csv = JSONToCSV(customers, { fields: ["Customer Name", "Business Name", "Customer Email", "Customer ID", "School ID", "Student Count", "Admin Count", "Courses Count" ]})
  
  const link = document.createElement('a')
  link.href = 'data:text/csv,' + encodeURIComponent(csv)
  link.download = 'customers.csv'
  link.click()
}

这当然假设您可以在前端提供 JSONToCSV 库,或者您将添加自己的函数来构建 CSV 数据。