Ionic Native HTTP instead of angulars http

If I am not wrong, we could use cordova-HTTP plugin instead of angular’s http lib to make http requests to server.

Ionic has wrapped this plugin with https://ionicframework.com/docs/native/http/ which is great.

We have a custom HTTP provider in our app which we load in app.module.ts in this way

export function httpFactory(backend: XHRBackend, options: RequestOptions) {
    return new HttpService(backend, options);

providers: [
        {
            provide: Http,
            useFactory:  httpFactory,
            deps: [
                XHRBackend,
                RequestOptions
            ]
        },

So we can declare angulars http in our services but under the hoot is used our custom service.

The cordova plugin is not workin in browser, so how could we use dynamically on browser the angulars http and on mobile devices the cordova plugin?
Is something like that possibile?

Thx

3 Likes

Why would you want to do that?

There is a Platform which has a is method: Platform | Ionic Platform to Customize Apps to Fit Any Device

1 Like

Why would you want to do that?

Because we have the necessary to call a self signed ssl certificate from device and also we have the necessary to remove the Origin: //file header from request.

As we use one app for webapp and mobile app which works very good for our use case, we would share code between different platforms.
In this case we have an HTTP interceptor so in our code we inject our HTTPService instead of HTTP, and in this interceptor we call the super classes of angulars HTTP. We would try to check the platform and load native HTTP instead of angulars http.

1 Like

Ok, then what I posted seems like a valid way forward.

I had almost the same problem. We need to implement certificate pinning, but I also want to run the app on browser. So I wrote a wrapper Provider as follows:

providers/http/http.ts

import {Injectable} from '@angular/core';
import {Platform} from 'ionic-angular';

import {HttpAngularProvider} from '../http-angular/http-angular';
import {HttpNativeProvider} from '../http-native/http-native';

@Injectable()
export class HttpProvider {
    public http;

    constructor(private platform: Platform, private angularHttp: HttpAngularProvider, private nativeHttp: HttpNativeProvider) {
        this.http = this.platform.is('ios') || this.platform.is('android') ? nativeHttp : angularHttp;
    }
}

providers/http-angular/http-angular.ts

import {Injectable} from '@angular/core';
import {Http, RequestOptions, ResponseContentType, URLSearchParams} from '@angular/http';

import 'rxjs/add/operator/map';

@Injectable()
export class HttpAngularProvider {
    constructor(public http: Http) {}

    public get(url, params?: any, options: any = {}) {
        let requestOptions = new RequestOptions();
        requestOptions.withCredentials = true;

        requestOptions.params = params ? this.createSearchParams(params) : requestOptions.params;

        return this.http.get(url, requestOptions).map(resp => options.responseType == 'text' ? resp.text() : resp.json());
    }

    public post(url, params: any, options: any = {}) {
        let requestOptions = new RequestOptions();
        requestOptions.withCredentials = true;

        let body = this.createSearchParams(params);

        return this.http.post(url, body, requestOptions).map(resp => options.responseType == 'text' ? resp.text() : resp.json());
    }

    private createSearchParams(params: any) {
        let searchParams = new URLSearchParams();
        for (let k in params) {
            if (params.hasOwnProperty(k)) {
                searchParams.set(k, params[k]);
            }
        }

        return searchParams;
    }
}

providers/http-native/http-native.ts

import {Injectable} from '@angular/core';
import {HTTP} from '@ionic-native/http';

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/fromPromise';
import 'rxjs/add/operator/map';

@Injectable()
export class HttpNativeProvider {
    constructor(public http: HTTP) {}

    public get(url, params?: any, options: any = {}) {
        let responseData = this.http.get(url, params, {})
            .then(resp => options.responseType == 'text' ? resp.data : JSON.parse(resp.data));

        return Observable.fromPromise(responseData);
    }

    public post(url, params?: any, options: any = {}) {
        let responseData = this.http.post(url, params, {})
            .then(resp => options.responseType == 'text' ? resp.data : JSON.parse(resp.data));

        return Observable.fromPromise(responseData);
    }
}

It successfully switches to native http on Android and iOS, and to angular http on browser. However, I have the problem with native http won’t persist the sessions, I guess it doesn’t send the cookies on subsequent calls.

3 Likes

This is a great solution, we have workaround the problem doing it a little bit different, because there it was much easier to share more code.
But at the end we rollback to xhr request because it was not easy to share cookies from native HTTP to Websocket calls.

So for now we use still XHR calls, but honestly we didn’t have any problem with cookies and native HTTP on android we used another cordovo projekt instead of the default one, but in meantime ionic switched by the default to it.

So are you on latest ionic native?

It turned out that the problem was not on the cookie handling of native plugin. There is a strange situation with redirections and setting cookies from the backend. Since I have already spent quite a lot of time debugging it, I had to postpone this feature. I’ll look into that soon again.

In general, the backend makes a redirection on the same response on which it is also setting some cookies. I don’t know yet, why it doesn’t work with native HTTP but works with Angular Http.

1 Like

Here is the updated version, adjusted for the latest Ionic version with Angular 5 and RxJS 5.5:

providers/http/http.ts

import {Injectable} from '@angular/core';
import {Platform} from 'ionic-angular';

import {HttpAngularProvider} from '../http-angular/http-angular';
import {HttpNativeProvider} from '../http-native/http-native';

@Injectable()
export class HttpProvider {
    public http: HttpNativeProvider | HttpAngularProvider;

    constructor(private platform: Platform, private angularHttp: HttpAngularProvider, private nativeHttp: HttpNativeProvider) {
        this.http = this.platform.is('ios') || this.platform.is('android') ? this.nativeHttp : this.angularHttp;
    }
}

providers/http-angular/http-angular.ts

import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';

@Injectable()
export class HttpAngularProvider {
    constructor(public http: HttpClient) {}

    public get(url: string, params?: any, options: any = {}) {
        options.params = params;
        options.withCredentials = true;

        return this.http.get(url, options);
    }

    public post(url: string, params: any, options: any = {}) {
        options.withCredentials = true;

        let body = this.createSearchParams(params);

        return this.http.post(url, body.toString(), options);
    }

    private createSearchParams(params: any) {
        let searchParams = new URLSearchParams();
        for (let k in params) {
            if (params.hasOwnProperty(k)) {
                searchParams.set(k, params[k]);
            }
        }

        return searchParams;
    }
}

providers/http-native/http-native.ts

import {Injectable} from '@angular/core';
import {HTTP} from '@ionic-native/http';

import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/fromPromise';

@Injectable()
export class HttpNativeProvider {
    constructor(public http: HTTP) {}

    public get(url: string, params?: any, options: any = {}) {
        let responseData = this.http.get(url, params, {})
            .then(resp => options.responseType == 'text' ? resp.data : JSON.parse(resp.data));

        return Observable.fromPromise(responseData);
    }

    public post(url, params?: any, options: any = {}) {
        let responseData = this.http.post(url, params, {})
            .then(resp => options.responseType == 'text' ? resp.data : JSON.parse(resp.data));

        return Observable.fromPromise(responseData);
    }
}```
5 Likes

Hi deggial,

We too facing same issue. How do we consume the created wrapper. Any help code snippet is appreciated.

Our code using Angular http is below
this.http.post(url, postParams, options).map(res => res.json()).subscribe(

1 Like

Hi @virtualbankingapp

I assume that you are using Angular < v5, then you should take my first example.

To consume it, you should import the wrapper provider instead of Angular’s Http Module, wherever you need Http. See the example below, I have commented the code parts.

import {Injectable} from '@angular/core';
// We are importing here the wrapper, instead of Angular's Http module.
import {HttpProvider} from '../http/http'; 

@Injectable()
export class SampleProvider {
    constructor(public http: HttpProvider) {
    }

    public sampleMethod() {
        // Here is a sample usage of the Http-Wrapper
        // Note that you don't need to map the response as 'res => res.json()' ,
        // since this is done in the wrapper, unless you pass in options:
        // {'responseType: 'text'}
        let url = 'example.com';
        let postParams = {};
        let options = {};
        this.http.post(url, postParams, options).subscribe();
    }
}

I hope this helps.

Hi Deggial,

I have implemented the code but when i run the app in device getting error “ERROR Error: Uncaught (in promise): Error: No provider for HTTP!”…

Do i have to register it in app.module.ts.
I have wrote in app.module.ts “import { HTTP } from ‘@ionic-native/http’;”

Am i missing any steps? or what should i do now w.r.t certificate pinning. Please help to fix this issue.

Read and follow the docs: https://ionicframework.com/docs/native/#Add_Plugins_to_Your_App_Module

Thanks for the reply…
In app.module.ts

Add import { HTTP } from ‘@ionic-native/http’;
Add HTTP into providers: [ … HTTP …];
It worked for me (:

Hello,

I created a new Ionic app yesterday (angular 5.0.0 and platform android 6.3.0), to verify if the angular/common/http/httpClient do all the SSL verification.

app.component.ts:

import { Component } from '@angular/core';
import { Platform } from 'ionic-angular';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';

import { TabsPage } from '../pages/tabs/tabs';
import { HttpClient } from '@angular/common/http';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  rootPage: any = TabsPage;

  constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen,
    private http: HttpClient) {
    platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      statusBar.styleDefault();
      splashScreen.hide();

      let urls = ['https://expired.badssl.com/',
        'https://wrong.host.badssl.com/',
        'https://self-signed.badssl.com/',
        'https://untrusted-root.badssl.com/',
        'https://revoked.badssl.com/',
        'https://pinning-test.badssl.com/'];

      for (const url of urls) {
        console.log(`Trying url ${url}`);
        this.http.get(url, { responseType: 'text' })
          .subscribe(response => {
            console.log(`SUCCESS for url ${url}, response: ${response}`);
          },
            error => {
              console.log(`ERROR for url ${url}, response: ${JSON.stringify(error)}`);
            });
      }
    });
  }
}

Seems like httpClient doesn’t check if the SSL certificate is valid:

03-29 12:19:13.697 4750-4750/io.ionic.starter I/chromium: [INFO:CONSOLE(318)] "SUCCESS for url https://untrusted-root.badssl.com/, response: <!DOCTYPE html>
                                                          <html>
                                                          <head>
                                                            <meta name="viewport" content="width=device-width, initial-scale=1">
                                                            <link rel="shortcut icon" href="/icons/favicon-red.ico"/>
                                                            <link rel="apple-touch-icon" href="/icons/icon-red.png"/>
                                                            <title>untrusted-root.badssl.com</title>
                                                            <link rel="stylesheet" href="/style.css">
                                                            <style>body { background: red; }</style>
                                                          </head>
                                                          <body>
                                                          <div id="content">
                                                            <h1 style="font-size: 8vw;">
                                                              untrusted-root.<br>badssl.com
                                                            </h1>
                                                          </div>
                                                          
                                                          <div id="footer">
                                                            The certificate for this site is signed using an untrusted root.
                                                          </div>
                                                          
                                                          </body>
                                                          </html>
                                                          ", source: file:///android_asset/www/build/main.js (318)

I did the same test with a sample Angular 5 project, calling same urls in app.component.ts and realised that Chrome validate the SSL certificate:

So the angular/common/http/httpClient validate the SSL certificate in a Angular project but not in a Ionic project ?
I must switch to ionic-native/http ?
Is it because of my old Ionic version ?
ionic info:

cli packages: (C:\Users\...\AppData\Roaming\npm\node_modules)

    @ionic/cli-utils  : 1.13.0
    ionic (Ionic CLI) : 3.13.0

global packages:

    cordova (Cordova CLI) : not installed

local packages:

    @ionic/app-scripts : 3.1.0
    Cordova Platforms  : android 6.3.0
    Ionic Framework    : ionic-angular 3.9.2

System:

    Android SDK Tools : 26.0.1
    Node              : v6.9.5
    npm               : 4.2.0
    OS                : Windows 7

Misc:

    backend : pro

Thanks for your help !

Hi Deggial,

I am using this plugin for certificate pinning. i have build the app by implementeing the steps as mentioned in the Ionic page https://ionicframework.com/docs/native/http/

But my android request and response are seen in burp suite. I need to fix this as soon as possible.
I have used it like below for each request.
this.http.setHeader(‘Access-Control-Allow-Origin’, ‘*’);
this.http.enableSSLPinning(true);
//this.http.acceptAllCerts(true); //commenting this with valid SSL certificate works but not worked with self signed certificate
this.http.setRequestTimeout(180);//3 minutes

What is the best way to implement if my steps are wrong

Please help me solve this so that i can try it on iOS App.

Hi All,

Doing certificate pinning to avoid man in the middle attack.

For information to you and others, it was problem with the certifcate , when i setup proper certificate at the server able to achived now in Android.
I have successfully now done the Certificate pinning in Android but facing issue in IOS. Giving error error : “Cancelled” & status: -1 in IOS.
Checked with this.http.enableSSLPinning(true); only first time and second time used
this.http.enableSSLPinning(true);
this.http.acceptAllCerts(true);

taken help from link https://github.com/silkimen/cordova-plugin-advanced-http/issues/9

Should i do somthing extra in IOS to acheive certificate pinning to avoid Man in the middle attack.

Thanking you in anticipation

Hi folks, can we not omit using native plugin if we use android Network Security Configuration

https://developer.android.com/training/articles/security-config.html

In this case we can trust a self signed certificate and we can do an SSL call with XHR also with local self signed certs.

Right?

Hi deggial,
I have successfull implemented certificate pinning with the help of cordova-plugin-advanced-http plugin.
Kindly help me regarding error coming most of the time i login. Login is inconsistent. Sometimes able to login but many times giving below errors
1)There was an error with the request: java.net.ConnectException: Failed to connect to “url”
2)The request is timeout

Kindly help me i am stuck in this and project cannot be successfull if this login inconsistency persist.

Does anyone face such issues. What can be the cause of this issue? Kindly enlighten in this subject.

To fix the issue of timeout i tried below IONIC forums links but not succeeded.

Thanks & Regards

Hi,

Good day.

When I do a this.http.get() it says the following:
Property ‘get’ does not exist on type ‘HttpProvider’.

What could I be doing wrong? If I do a console.log on this.http I get the following:

Seems it should work, but it does not.

Regards.
JJ

hI, I facing the same issue. did you find a solution? thanks