Unable to carryout HTTP post on Android

I am building a mobile application. When i want to test the login part on an android device i kept getting
{“headers”:{“normalizedNames”:{},“lazyUpdate”:null,“headers”:{}},“status”:0,“statusText”:“Unknown Error”,“url”:null,“ok”:false,“name”:“HttpErrorResponse”,“message”:“Http failure response for (unknown url): 0 Unknown Error”,“error”:{“isTrusted”:true}}

i searched online and implemented all recommendations but nothing seems to work. I have done ```


I am using nodejs as the backend API and i have enable cors on the index.js file
app.use(cors());
app.use(express.json()); // req.body

When i tried the application on the browser and Postman i did not get error but on the android mobile device nothing seems to work on Https:// and Http api domain

I will need a help on how this can be resolved

For production, you should be using https.

For development, you can set the clearText to true in the capacitor.config - Reference.

If clearText doesn’t work for you, you can set the Network security configuration directly in your Android config.

AndroidManifest.xml

<application
  ...
  android:networkSecurityConfig="@xml/network_security_config"
  ...
>
...
</application>

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
   <domain-config cleartextTrafficPermitted="true">
        <domain>YOUR_LOCAL_DOMAIN</domain>
   </domain-config>
</network-security-config>

I am using Angular and not capacitor

Your not building your app into a native Android app with Capacitor?

No. I am using Ionic Angular Cordova.

i have updated the network_security_config.xml as shown below

	<?xml version="1.0" encoding="utf-8"?>
	<network-security-config>
		<base-config cleartextTrafficPermitted="true">
  		  <trust-anchors>
         <certificates src="system" />
   		 <certificates src="user" />
    </trust-anchors>
	 </base-config>
   	 <domain-config cleartextTrafficPermitted="true">
  	  <domain includeSubdomains="true">localhost</domain>
  		  <domain includeSubdomains="true">mydomain.com</domain>
  		   <domain includeSubdomains="true">api.mydomain.com</domain>
		</domain-config>
		</network-security-config>

Also, i have modified the config.xml 

	<platform name="android">
	      <access origin="*" />
	     <preferance name="android:usesCleartextTraffic" value="true" />
		    <allow-navigation href="*" />
		    <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" 			xmlns:android="http://schemas.android.com/apk/res/android">
 		       <application android:networkSecurityConfig="@xml/network_security_config" />
  		      <application android:usesCleartextTraffic="true" />
   			 </edit-config>

And lastly, my node js Endpoint index.js has the below entries

const express = require(‘express’);
const app = express();
const cors = require(‘cors’);

app.use(cors());
app.use(express.json());

var http = require(‘http’);

http.createServer(function (request, response) {
response.writeHead(200, {
‘Content-Type’: ‘application/json’,
‘Access-Control-Allow-Origin’ : ‘*’,
‘Access-Control-Allow-Methods’: ‘GET,PUT,POST,DELETE’
});

});

// Here is used to import Routes
const thubsRoutes = require(’./users/routes’);

I have done everything but it is still not working.
My HTTP call from the ionic 5 application is :

addPerson(person:any): Observable {
this.httpHeader = {
headers: new HttpHeaders({ ‘Access-Control-Allow-Origin’:’*’,
‘content-type’: ‘application/json’,
‘Content-Type’: ‘application/x-www-form-urlencoded’,
‘Access-Control-Allow-Headers’:‘Origin, X-Requested-With, Content-Type, Accept’
})
};
console.log(person)
return this.http.post(this.baseURL + ‘login’, person,this.httpHeader)
}

Please assist.

First, get rid of all the custom headers. The CORS ones are for servers, not clients. You are setting conflicting content types, and you shouldn’t be setting any at all. Let HttpClient do its job and get out of its way. The type of the second parameter to post determines everything. If it’s a FormData, it’ll be form-encoded. If it’s an object, it’ll be JSON.

Secondly, see if your problem persists even when using HTTPS.

the same problem is also on HTTPS

I have also modified the headers

httpHeader= {
headers: new HttpHeaders({ ‘Content-Type’: ‘application/json’ })
};

You should have no custom HTTP headers at all. If you attach the Chrome Developer Tools to the app, its Network tab should allow you to see the exact headers and body of the request that is going over the wire (and that which comes back). You can then use a tool like Postman or netcat to take the Ionic app totally out of the equation. The server logs should tell you what the server is seeing.

If the server sees nothing whatsoever, then the problem is in the client app. That would be expected if it was a cleartext security problem, but you say the problem persists when using HTTPS, so I would be surprised if the server isn’t seeing anything. If the server is seeing something, then is it responding properly or with an error? If an error, the details of the error should help narrow down the problem.

i did a post without a custom header just as you have instructed :slight_smile: const

options = {
method: ‘POST’,
body: JSON.stringify( this.postData)
}

if (form.valid) {
  this.localhost = environment.apiUrl;
   fetch(this.localhost+ "login", options)
  .then(async response => {
    console.log(response);
    if (response.ok) {
      const data = await response.json();
          }
  })
  .catch(e => {
    console.log(e);
    })

and the error message is:

Access to fetch at ‘http://api.mydomain.com/api/v.0.1/theapi/login’ from origin ‘http://localhost:8101’ has been blocked by CORS policy: The ‘Access-Control-Allow-Origin’ header has a value ‘http://api.mydomain.com’ that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the request’s mode to ‘no-cors’ to fetch the resource with CORS disabled.

That would suggest the problem lies on the server side. Incidentally, I thought we had graduated to HTTPS.

I was able to solve the problem by adding the below at the server index.js file (it depends on what u save us with)

app.use((req, res, next) => {
res.header(‘Cache-Control’, ‘private, no-cache, no-store, must-revalidate’);
res.header(‘Expires’, ‘-1’);
res.header(‘Pragma’, ‘no-cache’);
res.header(‘Access-Control-Allow-Origin’, req.headers.origin || ‘*’);
res.header(‘Access-Control-Allow-Headers’, ‘Origin, X-Requested-With, Content-Type, Accept’);
res.header(‘Access-Control-Allow-Credentials’, ‘false’);
next();
});

and at the ionic angular client end i used the below header

httpHeader= {
headers: new HttpHeaders({ ‘Content-Type’: ‘application/json’ })
};

also to allow HTTP call from the mobile device, I did the below

network-security-config file:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
	<base-config cleartextTrafficPermitted="true">
	  <trust-anchors>
     <certificates src="system" />
	 <certificates src="user" />
</trust-anchors>
 </base-config>
 <domain-config cleartextTrafficPermitted="true">
  <domain includeSubdomains="true">localhost</domain>
	  <domain includeSubdomains="true">mydomain.com</domain>
	   <domain includeSubdomains="true">api.mydomain.com</domain>
	</domain-config>
	</network-security-config>

config.xml file

<platform name="android">
      <access origin="*" />
     <preferance name="android:usesCleartextTraffic" value="true" />
	    <allow-navigation href="*" />
	    <edit-config file="app/src/main/AndroidManifest.xml" mode="merge" target="/manifest/application" 			xmlns:android="http://schemas.android.com/apk/res/android">
	       <application android:networkSecurityConfig="@xml/network_security_config" />
	      <application android:usesCleartextTraffic="true" />
		 </edit-config>

Please don’t do this. It’s pointless, easy to shoot yourself in the foot with, and will confuse anybody else familiar with Angular’s HttpClient.

HttpClient is smart. Let it do its job and stay out of its way. It inspects the body argument you give to any of its methods that take one, and sets Content-Type appropriately: application/json for objects and application/x-www-form-urlencoded if you feed it HttpParams.