1
votes

I'm working on an ionic-angular app and post request is working fine when tested on browser using ionic serve but when excecuted on anroid device or emulator, the request doesn't work.

The backend is a rest api using slim php and xampp on windows server

The response for the request in android device is:

{"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"http://<>/ws_login.php/login","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://<>/ws_login.php/login: 0 Unknown Error","error":{"isTrusted":true}}

My login code looks like:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { HttpClientModule, HttpClient, HttpHeaders } from '@angular/common/http';
import { AuthConstants } from '../config/auth-constants';
import { ToastService } from './../services/toast.service';
import { LoadingService } from './../services/loading.service';
import { StorageService } from './../services/storage.service';
import { environment } from '../../environments/environment';

@Component({
    selector: 'app-login',
    templateUrl: './login.page.html',
    styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
    data = {
        user : '',
        pass : ''
    }

    constructor(
        public http: HttpClient, 
        private router: Router, 
        private toastService: ToastService,
        private loadingService: LoadingService,
        private storageService: StorageService
    ) { }

    ngOnInit() {
        this.storageService.get(AuthConstants.AUTH).then(
            data => data?this.router.navigate(["home"]):null
        )
    }

    login() {
        var headers = new HttpHeaders();
        headers.append("Accept", 'application/json');
        headers.append('Content-Type', 'application/json' );
        const requestOptions = { headers: headers };

        if(this.data.user == "" || this.data.pass == "")
            return this.toastService.presentToast("Debe completar ambos campos", "danger");

        this.loadingService.showLoading("Iniciando sesión");
        console.log(environment.apiUrl+'ws_login.php/login');
        this.http.post(environment.apiUrl+'ws_login.php/login', this.data, requestOptions).subscribe(
            resp => {
                this.loadingService.hideLoading();
                if(resp){
                    if(resp['error'] == 1)
                        this.toastService.presentToast(resp['mensaje'], "danger");
                    else{
                        this.storageService.store(AuthConstants.AUTH, 1);
                        this.toastService.presentToast("Sesión iniciada con éxito", "success");
                        this.router.navigate(["home"]);
                    }
                }
                else
                    this.toastService.presentToast("Error de red", "danger");
            }, 
            error => {
                this.data.user = JSON.stringify(error);
                this.loadingService.hideLoading();
                this.toastService.presentToast("Error de red", "danger");
            }
        );/*
        console.log(AuthConstants.AUTH);
        AuthConstants.AUTH = {id: 1};*/
        //this.router.navigate(["home"]);
    }
}

I also test the api using a rest app on device and the same url answers without problem.

I added android:usesCleartextTraffic="true" to androd manifest and was not the solution.

Here mi ionic info

Ionic:

   Ionic CLI                     : 6.3.0 (C:\Users\Manu\AppData\Roaming\npm\node_modules\@ionic\cli)
   Ionic Framework               : @ionic/angular 5.0.7
   @angular-devkit/build-angular : 0.803.26
   @angular-devkit/schematics    : 8.3.26
   @angular/cli                  : 8.3.26
   @ionic/angular-toolkit        : 2.2.0

Capacitor:

   Capacitor CLI   : 2.0.0
   @capacitor/core : 2.0.0

Utility:

   cordova-res : 0.11.0
   native-run  : 0.3.0

System:

   NodeJS : v12.16.1 (C:\Program Files\nodejs\node.exe)
   npm    : 6.13.4
   OS     : Windows 10

Thanks!

3
Try android:usesCleartextTraffic stackoverflow.com/a/59310320/5909026 in this way - Najam Us Saqib
Still same error - Manolo

3 Answers

1
votes

Since the error says that you are posting to http://<>/ws_login.php/login, I guess that there is a mistake in your environment variable apiUrl, when you deploy to mobile. If you serve the app on your developer machine, it will take the environment.ts to get the variables. Maybe you build the app for your phone in production and thus don't get the right environment variables (since Ionic then uses environment.prod.ts?

0
votes

Apparently angular httpClient has some issues when executed on native devices and emulators, my solution was migrating the request to ionic native http.

Thanks for the help!

0
votes

you can try ionic advance HTTP with mobile device https://ionicframework.com/docs/native/http, but it does not work with web browsers it only works in the mobile device. so you can try solution as check the platform and return HTTP service object as per users platform. example: if user platform==web then return Angular HttpClient else if user platform==Android/Ios then return Advnace Http object.

or you can use this code directly which has a wrapper around HTTP service,

import { Injectable } from '@angular/core';
import { Platform } from '@ionic/angular';
import { HttpClient } from '@angular/common/http';
import { HTTP } from '@ionic-native/http/ngx';
import { from, observable, Observable, of } from 'rxjs';
import { environment } from './../../environments/environment';
import { map, catchError } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})

export class HttpService {

  constructor(private platform: Platform, private httpclient: HttpClient, private http: HTTP) {
  }

  HttpRequest(method: 'POST'|'GET', url: string, requestBody: any): any
  {

    url = environment.serverBaseUrl + url;

    const headers = {};

    if (this.platform.is('ios') || this.platform.is('android') || this.platform.is('mobile'))
    {
    if (method === 'POST')
    {
      console.log('Advance_HTTP_POST');
      return from(this.http.post(url, requestBody, headers)).pipe(map((data: any) => JSON.parse(data?.data)));
    } else if (method === 'GET')
    {
      console.log('Advance_HTTP_GET');
      return from(this.http.get(url, {}, headers)).pipe(map((data: any) => JSON.parse(data?.data)));
    }
  } else {
    if (method === 'POST')
    {
      console.log('HTTPClient_HTTP_POST');
      return this.httpclient.post(url, requestBody, {headers});
    } else if (method === 'GET')
    {
      console.log('HTTPClient_HTTP_GET');
      return this.httpclient.get(url, {headers});
    }
    }
  }
}