How works cors in capasitor on real devices

I want to convert my angular web app to mobile app. I understand how works cors in web, there is just need to set port in frontend and the same port and url in backend allowedOrigins settings. But I can’t understand how does work cors in mobile app because IP is different in each mobile device, not static like in frontend.

I can config in my computer something like this:

In server:

app:
  auth:
  cors:
    allowedOrigins: http://127.0.0.1:8100,

In mobile app (capacitor.config.ts):

import { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.my.app',
  appName: 'my-mobile',
  webDir: 'dist/my-mobile',
  bundledWebRuntime: false,
  server: {
    cleartext: true,
    hostname: '127.0.0.1:8100',
  }
};

export default config;

And this works, but in locale, how to do it in prod, on real android devices?

In prod, the apps run at the following URL/origin by default:

  • iOS: capacitor://localhost
  • Android: http://localhost

So, both of those need to be configured in your backend as allowed origins. You could also use Capacitor’s HTTP plugin to get around CORS all together.

1 Like

How can the CapacitorHttp plugin get around CORS errors?

CORS is a browser specific security feature. Any HTTP requests outside a browser like from a backend server is not held to comply. With that, the Capacitor HTTP plugin uses native calls vs. through the embedded browser so it is not held to comply as well.

OK thanks. Although I can work around the CORS error by enabling the CapacitorHttp plugin, I wanted to avoid this, because it creates another problem: I can no longer save captured photos on Android (it works on iOS, but on Android only with disabled CapacitorHttp plugin).

const capturedPhoto = await Camera.getPhoto({
  resultType: CameraResultType.Uri,
  source: CameraSource.Prompt,
  quality: 100,
  saveToGallery: true
});

I get the errors below in the logs. Any idea how I can prevent CapacitorHttp from causing this?

22:44:00.330 Capacitor               D  Unable to find a Capacitor plugin to handle requestCode, trying Cordova plugins 168687845
22:44:00.336 Capacitor               D  App restarted
22:44:00.340 Capacitor               D  App started
22:44:03.859 Capacitor/AppPlugin     D  Firing change: true
22:44:03.860 Capacitor/AppPlugin     V  Notifying listeners for event appStateChange
22:44:03.860 Capacitor/AppPlugin     D  No listeners found for event appStateChange
22:44:03.860 Capacitor/AppPlugin     V  Notifying listeners for event resume
22:44:03.860 Capacitor/AppPlugin     D  No listeners found for event resume
22:44:03.860 Capacitor               D  App resumed
22:44:03.876 Capacitor               D  Handling local request: https://localhost/3483.551611b27004d02a.js
22:44:04.109 Capacitor               D  Handling local request: https://localhost/9588.df125b574ccb6f7d.js
22:44:04.481 Capacitor/Console       I  File: https://localhost/2934.5fe60317ed893572.js - Line 1 - Msg: captured photo:
22:44:04.487 Capacitor/Plugin        V  To native (Capacitor plugin): callbackId: 40608750, pluginId: CapacitorHttp, methodName: request
22:44:04.488 Capacitor               V  callback: 40608750, pluginId: CapacitorHttp, methodName: request, methodData: {"url":"https:\/\/localhost\/_capacitor_file_\/storage\/emulated\/0\/Android\/data\/io.ionic.starter\/files\/Pictures\/JPEG_20240107_224341_3627260566683712963.jpg","dataType":"json","headers":{}}
22:44:04.508 CapacitorCookies        I  Getting cookies at: 'https://localhost/_capacitor_file_/storage/emulated/0/Android/data/io.ionic.starter/files/Pictures/JPEG_20240107_224341_3627260566683712963.jpg'
22:44:04.530 Capacitor/Plugin        E  Failed to connect to localhost/127.0.0.1:443
                                        java.net.ConnectException: Failed to connect to localhost/127.0.0.1:443
                                        	at com.android.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:1418)
                                        	at com.android.okhttp.internal.io.RealConnection.connect(RealConnection.java:1368)
                                        	at com.android.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:219)
                                        	at com.android.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:142)
                                        	at com.android.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:104)
                                        	at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:392)
                                        	at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:325)
                                        	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:488)
                                        	at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:131)
                                        	at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.connect(DelegatingHttpsURLConnection.java:89)
                                        	at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:26)
                                        	at com.getcapacitor.plugin.util.CapacitorHttpUrlConnection.connect(CapacitorHttpUrlConnection.java:300)
                                        	at com.getcapacitor.plugin.util.HttpRequestHandler.request(HttpRequestHandler.java:419)
                                        	at com.getcapacitor.plugin.CapacitorHttp.lambda$http$0(CapacitorHttp.java:64)
                                        	at com.getcapacitor.plugin.CapacitorHttp.$r8$lambda$nEWv6LUu-usVqu2PfWDWH0J-AgQ(Unknown Source:0)
                                        	at com.getcapacitor.plugin.CapacitorHttp$$ExternalSyntheticLambda0.run(Unknown Source:6)
                                        	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:459)
                                        	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                                        	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
                                        	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
                                        	at java.lang.Thread.run(Thread.java:764)
22:44:04.532 Capacitor               D  Sending plugin error: {"save":false,"callbackId":"40608750","pluginId":"CapacitorHttp","methodName":"request","success":false,"error":{"message":"Failed to connect to localhost\/127.0.0.1:443","code":"ConnectException"}}
22:44:04.557 Capacitor/Console       D  File: https://localhost/ - Line 480 - Msg: CapacitorHttp fetch 1704663844477 https://localhost/_capacitor_file_/storage/emulated/0/Android/data/io.ionic.starter/files/Pictures/JPEG_20240107_224341_3627260566683712963.jpg: 66.0400390625 ms
22:44:04.561 Capacitor/Console       E  File: https://localhost/polyfills.441dd4ca9dc0674f.js - Line 1 - Msg: Unhandled Promise rejection: Failed to connect to localhost/127.0.0.1:443 ; Zone: <root> ; Task: null ; Value: Error: Failed to connect to localhost/127.0.0.1:443 Error: Failed to connect to localhost/127.0.0.1:443
                                            at returnResult (https://localhost/:857:32)
                                            at win.androidBridge.onmessage (https://localhost/:832:21)
22:44:04.569 Capacitor/Console       E  File: https://localhost/main.028c3d3aa2f4b6b5.js - Line 1 - Msg: ERROR Error: Uncaught (in promise): Error: Failed to connect to localhost/127.0.0.1:443
                                        Error: Failed to connect to localhost/127.0.0.1:443
                                            at returnResult (https://localhost/:857:32)
                                            at win.androidBridge.onmessage (https://localhost/:832:21)
22:44:30.601 Capacitor/AppPlugin     V  Notifying listeners for event pause
22:44:30.601 Capacitor/AppPlugin     D  No listeners found for event pause
22:44:30.602 Capacitor               D  App paused
22:44:30.649 Capacitor/AppPlugin     D  Firing change: false
22:44:30.649 Capacitor/AppPlugin     V  Notifying listeners for event appStateChange
22:44:30.650 Capacitor/AppPlugin     D  No listeners found for event appStateChange
22:44:30.650 Capacitor               D  App stopped
22:44:30.655 Capacitor               D  Saving instance state!
22:44:30.656 Capacitor               E  Couldn't save last Camera's Plugin getPhoto call

So I have updated all npm packages from capacitor & co. and the problem is gone now :man_shrugging:

Nice! The Capacitor team is always making improvements to the HTTP plugin so staying up-to-date is a good idea :grinning:

The error could be related to this fix in 5.4.2:

  • android: make local urls use unpatched fetch (#6954) (56fb853)