-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bug: CapacitorHttp - Requesting a Blob fails on native iOS and Android #6126
Comments
I can confirm this is still an issue with Capacitor 4.6.1 |
@KevinKelchen : on further investigation, it's less about 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. |
Phew... I thought I was the only one going crazy with this bug! Can also confirm in capacitor/core 4.6.1. I have even tried 'arraybuffer' for output and converting, but no dice. |
Without analysing quite enough yet, it does seem I am striking a related or at least very similar issue (I'm using capacitor/core 4.7.0). With the
And I get logs like this:
and get thrown an empty error object, which to me suggests that the HTTP GET part has succeeded, but the subsequent return as an ArrayBuffer object has failed. The same Angular Debugging the successful (Sidenote: The Typescript stuff seems a bit screwy for this, hence the weird |
I have the same problem like @markabrahams! With This is the error shown in Android Studio: E/Capacitor/Plugin: Failed to connect to localhost/127.0.0.1:80
java.net.ConnectException: Failed to connect to localhost/127.0.0.1:80
at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:147)
at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:116)
at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:186)
at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:128)
at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:97)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:289)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:232)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:465)
at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
at com.getcapacitor.plugin.util.CapacitorHttpUrlConnection.connect(CapacitorHttpUrlConnection.java:234)
at com.getcapacitor.plugin.util.HttpRequestHandler.request(HttpRequestHandler.java:410)
at com.getcapacitor.plugin.CapacitorHttp$1.run(CapacitorHttp.java:35)
at java.lang.Thread.run(Thread.java:1012)
D/Capacitor: Sending plugin error: {"save":false,"callbackId":"109383765","pluginId":"CapacitorHttp","methodName":"request","success":false,"error":{"message":"Failed to connect to localhost\/127.0.0.1:80","code":"ConnectException"}}
D/Capacitor/Console: File: http://localhost/ - Line 407 - Msg: CapacitorHttp fetch 1678198976081 http://localhost/_capacitor_file_/data/user/0/de.btcecho.app/files/magazine/ausgabe-66-dezember-2022.pdf: 11.80615234375 ms
E/Capacitor/Console: File: http://localhost/polyfills.js - Line 1220 - Msg: Unhandled Promise rejection: Failed to connect to localhost/127.0.0.1:80 ; Zone: <root> ; Task: null ; Value: Error: Failed to connect to localhost/127.0.0.1:80 Error: Failed to connect to localhost/127.0.0.1:80
at returnResult (http://localhost/:763:32)
at win.androidBridge.onmessage (http://localhost/:738:21) This is the Error shown in the Google Chrome console: polyfills.js:1220 Unhandled Promise rejection: Failed to connect to localhost/127.0.0.1:80 ; Zone: <root> ; Task: null ; Value: Error: Failed to connect to localhost/127.0.0.1:80
at returnResult (VM3:759:32)
at win.androidBridge.onmessage (VM3:734:21) Error: Failed to connect to localhost/127.0.0.1:80
at returnResult (http://localhost/:763:32)
at win.androidBridge.onmessage (http://localhost/:738:21) This is the function I am calling: import * as pdfjsLib from 'pdfjs-dist';
...
pdfjsLib.getDocument({
url,
cMapUrl: C_MAP_URL,
cMapPacked: true,
enableXfa: true
}); |
Seems like local requests through the native bridge using capacitor/core/native-bridge.ts Lines 413 to 416 in e486672
So maybe we have 2 issues here:
|
Count me in too on this issue I have to make HTTP GET requests to fetch images with authorization headers (so I can't use the When using Angular's HTTP client, everything works well When Capacitor HTTP is used (for CORS reasons), then everything stops working Related code : let url = 'some URL';
return this.headers$.pipe(
switchMap((headers) =>
// Works
this.http.get<any>(url, { headers, responseType: 'arraybuffer' })
// Workn't
/* from(
CapacitorHttp.get({
url,
headers,
responseType: 'arraybuffer',
}).then((response) => response.data)
) */
)
); |
As a workaround, one of my colleagues found this neat trick for images : CapacitorHttp.get({
url,
headers,
responseType: 'blob', // as any if needed
})
.then((response) => 'data:image/png;base64,' + response.data)) Didn't tested for other MIME types, but this one seems to work for images. Use the return value as a |
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. |
The problem is here capacitor/core/src/core-plugins.ts Lines 372 to 376 in 4b039f9
@ItsChaceDI see that it was you who added that line. Can you remember please why you convert blob and arraybuffer to base64 ? |
I can make a PR with correct behavior in case of blob and arrayBuffer, but it's important to understand if it won't break something internally. And most importantly, I think it should be at least a minor update since users might have problems |
Thanks @kwolfy - you're absolutely right! I can confirm success in downloading PDFs as arraybuffers if the Base64 encoding is removed. The native Android capacitor/android/capacitor/src/main/java/com/getcapacitor/plugin/util/HttpRequestHandler.java Lines 244 to 248 in 51a548b
And for iOS capacitor/ios/Capacitor/Capacitor/Plugins/HttpRequestHandler.swift Lines 134 to 137 in 51a548b
If I remove that Base64 encoding and just use UTF-8 string encoding to pass the arraybuffer/blob from the native handler to the JS and on the @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 |
this "fix" is making problems of requesting local data on native platforms. For exmaple also loading - window.open( I think Capacitor should create a better solution maybe, I am not sure why this PR was made (the one I tagged) |
No fix for this yet ? |
Found this issue where the original author explains this behavior: capacitor-community/http#176 |
any updates? |
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. |
idk how people can work with this for months... |
I can confirm the issue with this code as well. It works in the browser, but not on device, neither Android or iOS. One difference between browser and device is also that in the browser the blob in the response body already has the correct content type specified, but not in device, where it is always application/json and you have to manually first create the blob with the correct content type, but in browser it is possible to pass the response body directly to createObjectURL.
|
Here's a git diff showing our workaround for Capacitor v4. A quick look at the latest code in the master branch makes me think this would work for newer versions too.
|
This issue also occurs when using Mapbox gl js; when it tries to load the 3D layers as arrayBuffer, it fails
|
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Capacitor, please create a new issue and ensure the template is fully filled out. |
Bug Report
Capacitor Version
Platform(s)
Native iOS
Native Android
Current Behavior
Hello there! 👋
Using the Angular
HttpClient
, which usesCapacitorHttp
at a lower level, making a request to retrieve a Blob on native iOS and Android fails. Native iOS withoutCapacitorHttp
, Native Android withoutCapacitorHttp
, 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.0node --version
output: v16.17.0pod --version
output (iOS issues only): 1.11.3Additional Context
Thanks so much! 😀
Kevin
The text was updated successfully, but these errors were encountered: