From axios docs:
responseType: 'json',
'blob'
is a "browser only" option.
So from node.js, when you set responseType: "blob"
, "json"
will actually be used, which I guess fallbacks to "text"
when no parse-able JSON data has been fetched.
Fetching binary data as text is prone to generate corrupted data.Because the text returned by Body.text() and many other APIs are USVStrings (they don't allow unpaired surrogate codepoints ) and because the response is decoded as UTF-8, some bytes from the binary file can't be mapped to characters correctly and will thus be replaced by � (U+FFDD) replacement character, with no way to get back what that data was before: your data is corrupted.
Here is a snippet explaining this, using the header of a .png file 0x89 0x50 0x4E 0x47
as an example.
(async () => { const url = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png'; const buffer = await fetch( url ).then(resp => resp.arrayBuffer()); const header = new Uint8Array( buffer ).slice( 0, 4 ); console.log( 'binary header', header ); console.log( 'entity encoded', entityEncode( header ) ); const utf8_str = await new Blob( [ header ] ).text(); console.log( 'read as UTF-8', utf8_str ); const utf8_binary = [ ...utf8_str ].map( char => char.charCodeAt( 0 ) ); console.log( 'Which is binary', utf8_binary ); console.log( 'entity encoded', entityEncode( utf8_binary ) ); const fetched_as_text = await fetch( url ).then( resp => resp.text() ); const header_as_text = fetched_as_text.slice( 0, 4 ); console.log( 'fetched as "text"', header_as_text ); const as_text_binary = [ ...header_as_text ].map( char => char.charCodeAt( 0 ) ); console.log( 'Which is binary', as_text_binary ); console.log( 'entity encoded', entityEncode( as_text_binary ) ); })();function entityEncode( arr ) { return Array.from( arr ).map( val => 'U+' + toHex( val ) );}function toHex( num ) { return num.toString( 16 ).padStart(4, '0').toUpperCase();}
There is natively no Blob object in node.js, so it makes sense axios didn't monkey-patch it just so they can return a response no-one else would be able to consume anyway.
From a browser, you'd have exactly the same responses:
function fetchAs( type ) { return axios( { method: 'get', url: 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png', responseType: type } );}function loadImage( data, type ) { const new_blob = new Blob( [ data ], { type: 'image/jpg' } ); const url = URL.createObjectURL( new_blob ); img = document.getElementById( type + '_img' ); img.src = url; return new Promise( (res, rej) => { img.onload = e => res(img); img.onerror = rej; } );}[ 'json', 'text', 'arraybuffer', 'blob'].forEach( type => fetchAs( type ) .then( resp => loadImage( resp.data, type ) ) .then( img => console.log( type, 'loaded' ) ) .catch( err => console.error( type, 'failed' ) ));
<script src="https://unpkg.com/axios/dist/axios.min.js"></script><figure> <figcaption>json</figcaption> <img id="json_img"></figure><figure> <figcaption>text</figcaption> <img id="text_img"></figure><figure> <figcaption>arraybuffer</figcaption> <img id="arraybuffer_img"></figure><figure> <figcaption>blob</figcaption> <img id="blob_img"></figure>