Expecting Blob, Getting b64 string
Hello There,
I am making an http request and am expecting the response body to be a blob, however it seems that the request function internally converts the blob to a b64 string?
I assume this conversion is required for the download file functions, however I believe that this conversion code should be called there instead as I am expecting a blob response.
Here is the code in question. https://github.com/capacitor-community/http/blob/e675049b9b277bc4f4f0e6d446d107ebd183f447/src/request.ts#L138
Ended up fixing in my code with the following. (NOTE: This issue should still be fixed in the plugin)
// On Successful Response:
if (req.responseType === 'blob' && typeof body === 'string') {
// Capacitor Http Service converts blobs to b64, so we need to convert back to blob because that is what should be returned.
// Tracking issue here: https://github.com/capacitor-community/http/issues/176
body = this.b64toBlob(body, req.headers.get('Content-Type'));
}
B64 to blob conversion
/**
* Convert b64 string to a Blob
*
* @param {string} b64Data
* @param {string} contentType
* @param {number} sliceSize
* @returns {Blob}
* @private
* @see https://stackoverflow.com/a/16245768
*/
private b64toBlob(b64Data: string, contentType: string = '', sliceSize: number = 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);
}
return new Blob(byteArrays, {type: contentType});
}
Turns out that this is expected behavior within the plugin for a reason, even though it's not documented anywhere (as far as I can tell). When passing Javascript Objects from Javascript to the native code, the javascipt object/instances tend to loose their values/properties and functions, so an instance of Blob becomes an empty Js object. If the blob is turned into a b64 string it can be passed from Native app to Javascript without loosing any data. While this works and keeps the data from being lost, we should still be converting back to a blob in the javascript code, as that is the expected return type.
For some context, right now Capacitor doesn't support passing blobs to and from Web <--> Native. We're trying to figure out the best way to handle that since blobs can be huge and passing a 50Mb blob would massively impact performance.
That being said, this should probably be a flag or something to auto-convert back to a blob if a blob was passed in.
Agreed, I feel that if this is added as a flag it should be converted back to a blob by default.
A getAsBase64 flag which by default is false would be a good way to go about it I think. That way a user still has the baked in ability to get the object as a base 64 string but by default the return type is the type that is expected by a calling function.