Home » vue » Vue.js Axios responseType blob or json object

Vue.js Axios responseType blob or json object

Posted by: admin November 26, 2021 Leave a comment

Questions:

I have an Axios request to download the .xls file. Problem is that the object returned as a response from backend doesn’t always has to be a real file. If I return json object instead of file data. How I would read this json then?

Here is the function:

downloadReport() {
  let postConfig = {
    headers: {
      'X-Requested-With': 'XMLHttpRequest'
    },
    responseType: 'blob',
  } as AxiosRequestConfig

  axios
  .post(this.urls.exportDiscountReport, this.discount.id, postConfig)
  .then((response) => {
    let blob = new Blob([response.data], { type: 'application/vnd.ms-excel' });
    let url = window['URL'].createObjectURL(blob);
    let a = document.createElement('a');
    a.href = url;
    a.download = this.discount.id + ' discount draft.xlsx';
    a.click();
    window['URL'].revokeObjectURL(url);
  })
  .catch(error => {
  })
}

I would like to read the response and if it contains some data in it – don’t create the blob and initiate the download, instead, just show some message or whatever. If I remove the responseType: ‘blob’ then the .xls file downloads as unreadable and not valid file.

So the problem is that every returned response becomes blob type and I don’t see my returned data in it. Any ideas?

Answers:

I solved this by reading the blob response and checking if it has JSON parameter status. But this looks like an overengineering to me. Is there a better solution?

let postConfig = {
  headers: {
    'X-Requested-With': 'XMLHttpRequest'
  },
  responseType: 'blob',
} as AxiosRequestConfig

axios
  .post(this.urls.exportDiscountReport, this.discount.id, postConfig)
  .then((responseBlob) => {
    const self = this;
    let reader = new FileReader();

    reader.onload = function() {
      let response = { status: true, message: '' };

      try {
        response = JSON.parse(<string>reader.result);
      } catch (e) {}

      if (response.status) {
        let blob = new Blob([responseBlob.data], { type: 'application/vnd.ms-excel' });
        let url = window['URL'].createObjectURL(blob);
        let a = document.createElement('a');
        a.href = url;
        a.download = self.discount.id + ' discount draft.xlsx';
        a.click();
        window['URL'].revokeObjectURL(url);
      } else {
        alert(response.message)
      }
    }
    reader.readAsText(responseBlob.data);
  })
  .catch(error => {
  })

I also found the same solution here: https://github.com/axios/axios/issues/815#issuecomment-340972365

Still looks way too hacky.

###

Have you tried checking the responseBlob.type property? It gives the MIME type of the returned data.

So for example you could have something like this:

const jsonMimeType = 'application/json';
const dataType = responseBlob.type;

// The instanceof Blob check here is redundant, however it's worth making sure
const isBlob = responseBlob instanceof Blob && dataType !== jsonMimeType;

if (isBlob) {

  // do your blob download handling

} else {
  responseBlob.text().then(text => {
    const res = JSON.parse(text);
    // do your JSON handling
  });
}

This I find is much simpler and works for me, however it depends on your backend setup. The BLOB response is still a text response, but it’s handled slightly differently.