capacitor: bug: CapacitorHttp - Requesting a Blob fails on native iOS and Android
Bug Report
Capacitor Version
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 4.5.0
@capacitor/core: 4.5.0
@capacitor/android: 4.5.0
@capacitor/ios: 4.5.0
Installed Dependencies:
@capacitor/cli: 4.5.0
@capacitor/android: 4.5.0
@capacitor/core: 4.5.0
@capacitor/ios: 4.5.0
[success] iOS looking great! 👌
[success] Android looking great! 👌
Platform(s)
Native iOS Native Android
Current Behavior
Hello there! 👋
Using the Angular HttpClient
, which uses CapacitorHttp
at a lower level, making a request to retrieve a Blob on native iOS and Android fails. Native iOS without CapacitorHttp
, Native Android without CapacitorHttp
, and Web work fine.
In our production app, we use a POST request to retrieve a Blob, but using a GET seems to fail as well and was easier to use in a repro.
Expected Behavior
Native iOS and native Android should successfully retrieve the requested Blob.
Also, if we want CapacitorHttp
to work the same as XHR/fetch, this would be a difference.
Code Reproduction
https://github.com/KevinKelchen/capacitor-http-request-blob-issue#steps-to-reproduce
Other Technical Details
npm --version
output: 8.15.0
node --version
output: v16.17.0
pod --version
output (iOS issues only): 1.11.3
Additional Context
Thanks so much! 😀
Kevin
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 14
- Comments: 22
No fix for this yet ?
Requesting blob/arraybuffer via http client should return blob/arraybuffer, not some kind of base64 string. If it’s a technical problem, a conversion to proper type should be done on capacitor side. It’s misleading and makes using external components like
ngx-extended-pdf-viewer
orng-lazy-load-image
surprisingly broken. I already lost a few hours when debugging why PDFs and images does not load on mobile.@KevinKelchen : on further investigation, it’s less about
blob()
and more about requesting anything that isn’t a text/utf8 type file.So if I fetch an JSON endpoint and call blob, it works. But if I fetch an image, to save it locally, and call blob (or text() or any other method) it fails.
idk how people can work with this for months…
any updates?
Found this issue where the original author explains this behavior: https://github.com/capacitor-community/http/issues/176 Given the technical difficulty I think it’s acceptable that it keeps returning b64. It’s not like I’m doing some heavy computing and this extra encoding/decoding creates a huge problem for me. Someone else might be doing that though. However this definitely should be documented. Currently the doc has no mentioning on usage of b64, and
.data
happens to beany
. We ask for blob, there is aBlob
type, of course we expect it to beBlob
. Nonetheless it returns string. And now we are left to guess what the string is.Thanks @kwolfy - you’re absolutely right!
I can confirm success in downloading PDFs as arraybuffers if the Base64 encoding is removed.
The native Android
HttpRequestHandler.java
is encoding arraybuffers and blobs as Base64 here: https://github.com/ionic-team/capacitor/blob/51a548b97129998de8c403b2a8eb0421135af812/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java#L244-L248And for iOS
HttpRequestHandler.swift
here: https://github.com/ionic-team/capacitor/blob/51a548b97129998de8c403b2a8eb0421135af812/ios/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift#L134-L137If I remove that Base64 encoding and just use UTF-8 string encoding to pass the arraybuffer/blob from the native handler to the JS
CapacitorHttp
plugin, I receive the arraybuffer fine. e.g. for Android inHttpRequestHandler.java
replacing:return Base64.encodeToString(result, 0, result.length, Base64.DEFAULT);
with just UTF-8 encoding of the byte array:return new String(result, StandardCharsets.UTF_8);
and on the
CapacitorHTTP
plugin side removing the Base64 handling incore-plugin.ts
i.e. forarraybuffer
andblob
cases replace:data = await readBlobAsBase64(blob);
with just:data = blob;
@ItsChaceD - what is your take on this? Would a PR for such a change be accepted?
I can’t see this breaking anything, as I can’t see that arraybuffer or blob requests would ever work (unless a client assumed they would receive Base64 encoded blobs/arraybuffers, but that would be a very odd assumption for mind!) Importantly, this would align the arraybuffer/blob result using the
CapacitorHttp
plugin with the result without the plugin enabled, which is the goal for the plugin.The problem is here https://github.com/ionic-team/capacitor/blob/4b039f93d4c0b6b0665429cd573c073286734fc0/core/src/core-plugins.ts#L372-L376
@ItsChaceDI see that it was you who added that line. Can you remember please why you convert blob and arraybuffer to base64 ?
As a workaround, one of my colleagues found this neat trick for images :
Didn’t tested for other MIME types, but this one seems to work for images. Use the return value as a
img[src]
value, should display the image correctly.Just something to watch out for with this solution. It actually may point to what is happening internally causing the error this issue is about. You are getting back a base64 encoded string of the image, when it should be a blob. If the Capacitor team ever fix this issue your implementation of the get method above will break.