简体   繁体   中英

Capturing the error message downloading file with nodejs

I am download a file from nodejs.

When there is an error in backend, I need to send a message to front end.

My problem is that I am unable to capture that message.

I know there is some problem related to use blob and json, on back end.

But I didn´t solve it.

My code in line:

console.log(error.response.data.message)

allways returns "undefined"

//front end
    try{
        let response = await axios.post('/generateLoteXMLZIPConsulta');
        let blob = await new Blob([response.data], {
          type: "application/zip",
        });
        const link = document.createElement("a");
        link.style.display = "none";
        link.href = window.URL.createObjectURL(blob);
        const fileName = response.headers["content-disposition"].match(
          /filename=(.*)/
        )[1];
        link.download = fileName;
        link.click();
        window.URL.revokeObjectURL(link.href);
    }catch(error){
      console.log(error.response.data.message)
    }
         //backend nodejs
         router.post("/generateLoteXMLZIPConsulta", async (req, res) => {
            ....
            ....
            try
               res.download(
                    path.resolve(__dirname, "../../file.zip"),
                    "xmlFile.zip"
            );
            catch (error){
               res.removeHeader("Content-disposition");
               res.status(400).json({ message: "You got an error" });
            }
        })      

First of all, there are a few mistakes in your code:

...
  try {
    // you have to tell axios how to handle response with `responseType`
    let response = await axios.post('/generateLoteXMLZIPConsulta');

    // no need to use await here
    let blob = await new Blob([response.data], {
      type: "application/zip",
    });

    const link = document.createElement("a");

    // no need since you didn't append this element into DOM
    link.style.display = "none";

    link.href = window.URL.createObjectURL(blob);
    const fileName = response.headers["content-disposition"].match(
      /filename=(.*)/
    )[1];
    link.download = fileName;
    link.click();
    window.URL.revokeObjectURL(link.href);
  } catch (error) {
    console.log(error.response.data.message)
  }
...

This is my reproduce code:

// backend

app.post('/foo', async (req, res) => {
  try {
    // throw 'Something went wrong'
    res.download(path.resolve('bar.zip'))
  } catch {
    res.status(400).json({ message: 'You got an error' })
  }
})
// frontend

;(async function () {
  try {
    // with blob response you have no need to wrap response data to create blob again
    // {} is required otherwise axios will treat { responseType } as data
    let response = await axios.post('/foo', {}, { responseType: 'blob' })
    let blob = response.data
    console.log(window.URL.createObjectURL(blob))
  } catch (error) {
    console.log(error.response.data)
  }
})()

This is working so far except when backend throw an error, axios will treat the response as blob as we set. So we have to convert it back to json.

axios.interceptors.response.use(null, async error => {
  if (error.response.request.responseType === 'blob') {
    // you may need to add an error handler if the response is not JSON
    error.response.data = await new Promise(resolve => {
      let reader = new FileReader()
      reader.addEventListener('load', () => {
        resolve(JSON.parse(reader.result))
      })
      reader.readAsText(error.response.data)
    })
  }
  throw error
});

This is related Github issue .

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