С топор ios документы :
// `responseType` indicates the type of data that the server will respond with
// options are: 'arraybuffer', 'document', 'json', 'text', 'stream'
// browser only: 'blob'
responseType: 'json', // default
'blob'
- это опция "только для браузера".
node.js, когда вы устанавливаете responseType: "blob"
, на самом деле будет использоваться "json"
, что, как я полагаю, дает откат к "text"
, когда не извлекаются данные JSON с возможностью разбора.
Выборка двоичных данных как текст склонен генерировать поврежденные данные. Поскольку текст, возвращаемый Body.text () и многими другими API, является USVStrings (они не допускают непарные суррогатные кодовые точки) и поскольку ответ декодируется как UTF-8, некоторые байты из двоичного файла не могут быть правильно сопоставлены с символами и, таким образом, будут заменены символом замены U (U + FFDD), без возможности вернуть то, что было раньше: ваши данные повреждены.
Вот фрагмент, объясняющий это, используя в качестве примера заголовок файла .png 0x89 0x50 0x4E 0x47
.
(async () => {
const url = 'https://upload.wikimedia.org/wikipedia/commons/4/47/PNG_transparency_demonstration_1.png';
// fetch as binary
const buffer = await fetch( url ).then(resp => resp.arrayBuffer());
const header = new Uint8Array( buffer ).slice( 0, 4 );
console.log( 'binary header', header ); // [ 137, 80, 78, 61 ]
console.log( 'entity encoded', entityEncode( header ) );
// [ "U+0089", "U+0050", "U+004E", "U+0047" ]
// You can read more about (U+0089) character here
// https://www.fileformat.info/info/unicode/char/0089/index.htm
// You can see in the left table how this character in UTF-8 needs two bytes (0xC2 0x89)
// We thus can't map this character correctly in UTF-8 from the UTF-16 codePoint,
// it will get discarded by the parser and converted to the replacement character
// read as UTF-8
const utf8_str = await new Blob( [ header ] ).text();
console.log( 'read as UTF-8', utf8_str ); // "�PNG"
// build back a binary array from that string
const utf8_binary = [ ...utf8_str ].map( char => char.charCodeAt( 0 ) );
console.log( 'Which is binary', utf8_binary ); // [ 65533, 80, 78, 61 ]
console.log( 'entity encoded', entityEncode( utf8_binary ) );
// [ "U+FFDD", "U+0050", "U+004E", "U+0047" ]
// You can read more about character � (U+FFDD) here
// https://www.fileformat.info/info/unicode/char/0fffd/index.htm
//
// P (U+0050), N (U+004E) and G (U+0047) characters are compatible between UTF-8 and UTF-16
// For these there is no encoding lost
// (that's how base64 encoding makes it possible to send binary data as text)
// now let's see what fetching as text holds
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 ); // "�PNG"
const as_text_binary = [ ...header_as_text ].map( char => char.charCodeAt( 0 ) );
console.log( 'Which is binary', as_text_binary ); // [ 65533, 80, 78, 61 ]
console.log( 'entity encoded', entityEncode( as_text_binary ) );
// [ "U+FFDD", "U+0050", "U+004E", "U+0047" ]
// It's been read as UTF-8, we lost the first byte.
})();
function entityEncode( arr ) {
return Array.from( arr ).map( val => 'U+' + toHex( val ) );
}
function toHex( num ) {
return num.toString( 16 ).padStart(4, '0').toUpperCase();
}
В node.js изначально отсутствует объект Blob, поэтому имеет смысл, что ax ios не сделал обезьяньего патча, чтобы они могли вернуть ответ, который никто другой не сможет получить.
Из браузера вы получите точно такие же ответы:
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 ) {
// we can all pass them to the Blob constructor directly
const new_blob = new Blob( [ data ], { type: 'image/jpg' } );
// with blob: URI, the browser will try to load 'data' as-is
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', // will fail
'text', // will fail
'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>