【问题标题】:Express.JS response.download not downloading fileExpress.JS response.download 不下载文件
【发布时间】:2020-10-26 08:01:18
【问题描述】:

我在 Node.JS 服务器上工作,使用 Express 根据用户输入生成和下载 PDF。我使用 Axios POST 调用服务器,然后期望使用 Express 的 response.download() 下载文件。我最近从使用 <form action=""> 调用我的 API 的方法更改为 Axios,因为 Netlify 似乎不支持 NuxtAPI。该程序在旧版本中生成了所需的文件,但是对 Axios 的更改意味着它不再有效。

现在,没有文件被下载(即使是固定路径的文件,例如已发布网站上的文件),并且在提示下载之前页面正在重新加载。

我的代码如下:

print.vue:


<template>
<main>
     <button class="btn btn-primary" @click="submit">Print Certificate</button>
</main>
</template>
<script>
export default{
methods:{
        async submit(){
            try{
                let params = {
                    name: this.name,
                    kana: this.kana,
                    rank: this.rank,
                    date: this.date
                }
                // produces valid object in all cases
                await this.$axios.$post('/api/certificate', null, {params})
            }catch(err){
                console.log(err)
                alert(err)
            }
        }
    },
    computed:{ // functions from route params, resolve to these always for test case
    name: function(){return 'Test Student'},
    kana: function(){return "Tesuto Sutuudento"},
    rank: function(){return "8th Kyu"},
    date: function(){return '26th October, 2020"}
    }
}
</script>

/api/certificate.js

var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.post('/', urlencodedParser, function(req, res) {
    let response = {
      name: req.query.name,
      kana: req.query.kana,
      rank: req.query.rank,
      date: req.query.date
    }
    console.log(response)
    html = html.replace("{{name}}", response.name)
    html = html.replace("{{kana}}", response.kana)
    html = html.replace("{{rank}}", response.rank)
    html = html.replace("{{date}}", response.date) // always produces valid string (template)
    pdf.create(html, options).toFile('static/certificates/' + response.name.split(' ')[0] + '_' + response.rank.split(' ')[0] + '_' + response.rank.split(' ')[1] + '.pdf', function(err, rep){
        // file made with no difficulties
        if (err) return console.log(err);
        console.log(rep.filename) // gives absolute path (C:\\)
        //res.download('https://get.pxhere.com/photo/computer-screen-technology-web-internet-signage-page-coding-website-html-programming-font-design-text-digital-information-java-site-games-software-development-code-screenshot-data-script-www-css-computer-programming-web-developer-web-development-programming-code-web-page-website-development-670370.jpg') // test fixed path downloading
        //res.download(rep.filename,'my_pdf.pdf') // what I think the easiest solution should be
        res.download('static/certificates/' + response.name.split(' ')[0] 
        + '_' + response.rank.split(' ')[0] + '_' 
        + response.rank.split(' ')[1] + '.pdf') // what worked before
    })
})

总的来说,我对 API 和 Node 比较陌生,所以我缺少一些基本的东西吗?

【问题讨论】:

  • 我想你可以使用 fs 节点的模块,它非常完整,并使用 fs.writeFileSync 函数以 pdf 或任何格式写入数据 nodejs.org/api/fs.html#fs_fs_writefilesync_file_data_options
  • 您的表单看起来如何?听起来页面已重新加载,因为在客户端执行了默认操作。如果您使用 curl 或邮递员之类的工具来生成 http 请求,您的服务器端代码是否有效?
  • @Marc 没有使用表单,尽管它今天早上停止重新加载。所有数据都是从 URL 参数计算出来的
  • “this.name”在哪里定义?你的“
    ”在哪里?你的 html 是什么样子的?
  • @Marc this.name 等是基于路由参数的 Nuxt 计算属性。我已将代码包含为简单地返回他们为我的测试用例解析的内容。我已编辑以包含相关标记

标签: javascript node.js express nuxt.js


【解决方案1】:

原来Axios不喜欢下载TXT、HTML或JSON文件以外的任何东西,所以我们需要将生成的文件下载为arraybuffer,然后使用js-file-download将其转换为我们想要的文件格式。

下面的例子:

在我的服务器中

import Path from 'path'
import pdf from 'html-pdf'

    pdf.create(html, options).toFile('./mypdf.pdf', function(err, rep){
        if (err) return console.log(err);
        let path = Path.resolve(rep.filename) // ensures we always get the generated path
        console.log("resoved path:" + path)
        res.setHeader('Content-disposition', 'mypdf.pdf');
        res.download(path)

    })

在我的客户中:

methods:{
        async submit(){
            const fileDownloader = require('js-file-download');
            try{
                let params = {
                    name: this.name,
                    kana: this.kana,
                    rank: this.rank,
                    date: this.date
                }
                // use responseType to tell axios its a buffer, using $post instead of post is shorthand for post().data
                // not setting this header results in corrupted pdfs
                let response = await this.$axios.$post('/api/certificate', null, {params: params, responseType:'arraybuffer'})
                console.log(response) // gibberish because Adobe
                // create and immediately download. Since we don't want to give a choice, immediate download is fine 
                fileDownloader(response, 'mypdf.pdf') 
                
            }catch(err){
                console.log(err)
                alert(err)
            }
        }
    },

特别感谢 this answer 提供客户端标头,this answer 提供指向 js-file-downloader 的链接,感谢 this answer 提供服务器端响应标头。没想到这么麻烦。

【讨论】:

    【解决方案2】:

    我认为这会奏效

    了解更多关于writeFileSync

    
    const data = {
        Patient_name: result.patient_name,
        Doctor: result.doctor,
        Date: result.date,
        Time: result.time,
        Key: result.key
    };
    const path = `${process.cwd()}/public/UserData.csv`;
    fs.writeFile(path, data, function (err) {
        if (err) { throw err; }
        else {
            res.download(path);
            console.log(data);
        }
    })
    
    

    【讨论】:

    • 你必须写res.download()
    • 如果“pdf”未定义,res.download 会向客户端发送什么?!再次阅读我的评论和文档。 nodejs.org/api/…。请删除您的答案并重新考虑问题。同步版本没有回调...
    • 我已阅读,如果数据来自表单,它将创建,或者如果已经有一个名为 my.pdf 的文件,它将在该 pdf 中添加数据
    • 仍然“不工作”,因为您传递的回调永远不会被调用。为每个用户提供硬编码文件是一种不好的做法。您如何处理并发请求?用户 B 从用户 A 那里获取 pdf。太糟糕了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-16
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2020-05-02
    • 2015-04-18
    • 2016-05-25
    相关资源
    最近更新 更多