简体   繁体   中英

File responsed by response.download() and download as blob containing undefined

I'm building a client-server certificate generator.


On Backend I'm using two endpoints:

/
  • Receives a JSON containing data extracted from inputs, sanitize them, and returns if they're valid or not
/download
  • Receives whether data is valid or not. If it's, generate a certificate.pdf file and responses it with res.download(certificatePath)
  • I guess I should use some kind of token/authentication/authorization because someone could just ignore the first endpoint but I'll do that once the downloading itself is fixed

I think the problem with backend is in some of those functions:

const getCertificatePDF = (name, validValuesData, validValuesQty, response) => {
    // ... ommited for brevity
    pdf.create(document, options)
        .then(res => {
            console.log(res)
            let filePath = path.join(__dirname, 'certificate.pdf');
            console.log("FILE PATH: ", filePath);                            
            response.download(filePath, "certificate.pdf");
        })
        .catch(error => {
            console.error(error)
        });
}

app.post('/download', (req, res) => {
    const data = req.body;
    console.log("DATA", data);
    getCertificatePDF(data.name, data.validValuesData, data.validValuesQty, res)
});

On frontend , I chained both requisitions using promises, created a blob , created a link with download attribute for that blob and triggered an onClick :

const sendForm = (filledCodeValues, email, name) =>{
    // ...ommited for brevity

    fetch(url, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: data,
      })
        .then((res) => res.json())
        .then((processedData) => {
            alertAllFilledInvalid(processedData.validValuesQty)
            const dataString = JSON.stringify(processedData);
            if(processedData.validValuesQty > 0){
                console.log("DATA STRING ", dataString)
                const downloadUrl = url + "download";
                fetch(downloadUrl, {
                    method: "POST",
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: dataString,
                  })
                .then((res2) => {
                    res2.blob()
                })
                .then((blob)=>{
                    const newBlob = new Blob([blob]);
                    const newUrl = window.URL.createObjectURL(newBlob);

                    const link = document.createElement('a');
                    link.href = newUrl;
                    link.setAttribute('download', 'certificate.pdf');
                    document.body.appendChild(link);
                    link.click();
                    link.parentNode.removeChild(link);

                    window.URL.revokeObjectURL(newBlob);
                })
            }
        })
}

Issue

The issue is, the certificate.pdf downloaded by frontend is containing undefined :前端下载的未定义证书

I know the first request is correct, because the console.log() is printing the expected contents for stringData :

前端设法完成第一个请求

I also know the second request work, because on backend, certificate.pdf is being correctly generated :

后端正确接收第二次申请并生成pdf

Ps - i'm manually deleting certificate.pdf on backend to ensure it's a new one generated

Since certificate is being generated, I believe there's something wrong with either:

  1. Backend's response.download(filePath, "certificate.pdf");
  2. FrontEnd blob creating and downloading

I manually moved certificate(25).pdf (generated by frontend) to backend and run a script for reading both certificate.pdf (generated by backend) files, to test if the issue is on filePath using a readFiles.js script:

const fs = require('fs');
let path = require('path');

let filePath = path.join(__dirname, 'certificate.pdf');
console.log("FILE PATH: ", filePath);
fs.readFile(filePath, 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(">>>>> FilePath content <<<<< ", data);
});


let filePath2 = path.join(__dirname, 'certificate(25).pdf');
console.log("FILE PATH 2: ", filePath2);
fs.readFile(filePath2, 'utf8', (err, data) => {
    if (err) {
        console.error(err);
        return;
    }
    console.log(">>>> FilePath2 content <<<< ", data);
});

读取文件

It turns out the path is correct, and certificate.pdf (backend) has content, while certificate(25).pdf (frontend) has just an undefined value.


Can someone help me please?

You need to return the value of res2.blob() :

.then((res2) => {
  return res2.blob()
})

Or leave out the brackets:

.then((res2) => res2.blob())

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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