0

I have my code below from Backend that is working fine when I test it using Laravel's blade. But I can't do the same in using Axios in my React frontend (see frontend code below).

return (new NewsExport())->download($filename);

I somehow found some solutions from another site: they change the backend code, they use the Storage method to return a link instead of a file. But I don't want to use Storage, I want to prevent overstoring files (in case of a user in the frontend rapidly clicks the download button).

My question how can we download the returned file from the backend in the frontend Axios?


My frontend codes (the codes below successfully download an excel file, but the file is corrupted I think because I can't open it when I test it using Microsoft Excel)

let response = await newsApi.exportNewsList(payload).then(response => {
    const url = window.URL.createObjectURL(new Blob([response.data]));
    const link = document.createElement('a');
    link.href = url;
    link.setAttribute('download', 'exc.xlsx'); //or any other extension
    document.body.appendChild(link);
    link.click();
});

Here is the response.data when I log: screenshot

2 Answers2

5

I think you forgot to specify your responseType as blob in your api options.

const options = {
    method: 'POST',
    responseType: 'blob', <=== you need this one
    data: formData,
    url: '/yourApi',
};

return API.request(options);
tempra
  • 2,455
  • 1
  • 12
  • 27
0

It might be to do with how you are converting the response to a blob. Here is a block of code that I always use when I have to do something like this. I have formatted it to suit your code above so hopefully it will work the same way

const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
  const byteCharacters = atob(b64Data);
  const byteArrays = [];

  for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
    const slice = byteCharacters.slice(offset, offset + sliceSize);

    const byteNumbers = new Array(slice.length);
    for (let i = 0; i < slice.length; i++) {
      byteNumbers[i] = slice.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    byteArrays.push(byteArray);
  }

  const blob = new Blob(byteArrays, { type: contentType });
  return blob;
};

let response = await newsApi.exportNewsList(payload).then(response => {
  const dataBlob = b64toBlob(
    response.data,
    'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64'
  );
  const link = window.document.createElement('a');
  link.href = window.URL.createObjectURL(dataBlob);
  link.download = 'exc.xlsx';
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
});
Richard Hpa
  • 2,353
  • 14
  • 23
  • i got error **Unhandled Rejection (InvalidCharacterError): Failed to execute 'atob' on 'Window': The string to be decoded contains characters outside of the Latin1 range.** – アリ・ナディム Jun 08 '21 at 05:39
  • That probably means there is something in the spreadsheet that isn't formatted the way it wants. I found this link to another SO question that might solve the error you got https://stackoverflow.com/questions/23223718/failed-to-execute-btoa-on-window-the-string-to-be-encoded-contains-characte – Richard Hpa Jun 08 '21 at 05:43
  • I tried to download in Laravel Blade view. and it downloads successfully, and the file also opened in Microsoft Excel. – アリ・ナディム Jun 08 '21 at 05:45
  • I wonder if the axios is returning the right info then – Richard Hpa Jun 08 '21 at 05:48
  • here is the `response.data` when I log it https://prnt.sc/14nokkr – アリ・ナディム Jun 08 '21 at 05:50
  • That to me looks like you are actually returning the excel file rather than the excel data – Richard Hpa Jun 08 '21 at 05:59