How can I read http errors when responseType is blob in Axios with VueJs? [duplicate]
Asked Answered
T

7

33

I'm using blob responseType with Axios in my VueJS app for downloading a document from the server. When the response code is 200 it works fine and download the file but when there is any http error, I'm not able to read the status code when I catch the error because the error is a JSON response.

Has anyone had a similar issue and worked out a way to convert the blob response type to json and thrown an error based on the status code?

I have tried sending the response as a plain text from Laravel backend and tried converting the response to JSON or text in the front-end but no luck.

I have tried reading error response headers but no luck.

Axios({
        url: 'xxxx',
        method: 'GET',
        responseType: 'blob', 
        })
    .then((response) => {
        //code to read the response and create object url with the blob and download the document
    })
    .catch((error) => {
      console.log('Error', error.message); //nothing
      console.log('Error', error.error); //undefined
      console.log('Error', error.data); //undefined

      const blb    = new Blob([error], {type: "text/plain"});
      const reader = new FileReader();

      // This fires after the blob has been read/loaded.
      reader.addEventListener('loadend', (e) => {
        const text = e.srcElement.result;
        console.log(text);
      });
     // Start reading the blob as text.
     reader.readAsText(blb);
});

I just want to throw the error message based on the status code. If it's 401 just want it to be unauthorized and anything else throw it on to the component.

Tottering answered 24/5, 2019 at 5:30 Comment(4)
@tony19 nothing about blob in the question you mentioned.Pinafore
@Pinafore The responseType field has no bearing on the status code, which is accessed the same way regardless.Oquendo
You may find this helpful: Error Response for blob type. It's a similar issue with several solutions.Sarsaparilla
@Sai, please check whether one of the answers resolve your problem, and mark it as accepted.Bouton
B
21

The reason is that the response type is blob.
In case of error, the status code is available directly in your exception object. However, the response is a promise.

What you need to do is:

.catch((error) => {
    let statusCode = error.response.status
    let responseObj = await error.response.data.text();
       :
       :

For more details you can read documentation.

Bouton answered 15/6, 2021 at 11:6 Comment(1)
just parse responseObj to JSON and maybe throw a try catch around it... but thanks, saved me a lot of Reader stuff.Juliusjullundur
C
9

You can do this, it cast the error in JSON if it's a blob or let the response data as it received and you can do work with it.

  let errorString = error.response.data;
  if (
      error.request.responseType === 'blob' &&
      error.response.data instanceof Blob &&
      error.response.data.type &&
      error.response.data.type.toLowerCase().indexOf('json') != -1
  ) {
    errorString = JSON.parse(await error.response.data.text());
  }
  
  alert(errorString);
Colorblind answered 3/8, 2021 at 12:27 Comment(1)
Simple & works as expected.Henderson
T
5

You need to convert the response blob to json:

Axios({
    url: 'xxxx',
    method: 'GET',
    responseType: 'blob',
  })
  .then((response) => {
    //code to read the response and create object url with the blob and download the document
  })
  .catch((error) => {
    if (
      error.request.responseType === 'blob' &&
      error.response.data instanceof Blob &&
      error.response.data.type &&
      error.response.data.type.toLowerCase().indexOf('json') != -1
    ) {
      new Promise((resolve, reject) => {
          let reader = new FileReader();
          reader.onload = () => {
            error.response.data = JSON.parse(reader.result);
            resolve(Promise.reject(error));
          };

          reader.onerror = () => {
            reject(error);
          };

          reader.readAsText(error.response.data);
        })
        .then(err => {
          // here your response comes
          console.log(err.response.data)
        })
    };
  });

You can use this inside interceptor. For more info

Tauto answered 24/5, 2021 at 18:9 Comment(0)
D
1

I believe you might be using the error variable in your catch() incorrectly.

Axios passes an error object that has a response property that is where you will want to look for your error or message.

https://github.com/axios/axios#handling-errors

On a side note if you can catch the error server side you could try setting the Content-type header to text/plain. Using either header('Content-Type: plain/text') or Laravel's Response Methods

Dhar answered 8/12, 2020 at 14:54 Comment(0)
B
1

You can convert blob response globaly:

$axios.onError(async ({request, response}) => {
  const status = response.status

  let data = response.data

  if (request.responseType === 'blob' && data instanceof Blob && data.type) {
    const text = await data.text()

    data = data.type.toLowerCase().includes('json') ? JSON.parse(text) : text
  }

  throw {status, data} // error model
})
Babysitter answered 4/1, 2023 at 16:29 Comment(0)
I
0

you can do the following way

axios.post("URL", data, {
            validateStatus: (s) => s <= 500,
            responseType: 'blob',
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/pdf'
            }
        })
    .then(async (response) => {
        if (response.status !== 200) {
            // error handling
            const error = JSON.parse(await response.data.text());
            console.log('error: ', error);
            alert(error.message);
        } else {
            console.log('res', response)
            const url = window.URL.createObjectURL(new Blob([response.data]));
            const link = document.createElement('a');
            link.href = url;
            link.setAttribute('download', 'file.pdf'); //or any other extension
            document.body.appendChild(link);
            link.click();
        }
    })
Inflight answered 25/5, 2022 at 8:11 Comment(0)
G
-1
catch(async(error) => {
    const errorJson = JSON.parse(await error.response.data.text());
    console.log('error: ', errorJson.error_message);      
})
Gloam answered 14/2, 2023 at 15:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.