HTTP request not working on build app


#1

Hi every one !

I assigned my app to a channel and gave access to some users -> they can now load app in IONIC view and it launches well…

My issue is that that app cannot access my backend… :frowning:

Localhost testing works fine (with proxy set up). For this channel, I removed the proxy config and directly set the right url ('ex: ‘https://dev.myorg.com’ ) but an error rises :
Http failure response for (unknown url): 0 Unknown Error

I guess that’s just a config issue but can’t find out… any clue ??

Thx!

Salva.


#2

Can you share your code so that we can help


#3

Sure.

I’m trying to authenticate a user to our platform.

  1. LoginService:
  doConnect(userLogin: string, userPass: string, company: string): Observable<any> {
    let authorization = // Auth fction.;

    console.log('Authorization: ' + authorization);
    return this.httpService.get(this.loginUserUrl,
      {
        headers: new Headers({
          "X-Requested-With": "XMLHttpRequest",
          "Authorization": authorization
        })
      });
  }

httpService is a custom service (code found here…) allowing me to switch implemetation following current env (dev in browser or built app on cordova)

->

import { Injectable } from '@angular/core';
import { Platform } from 'ionic-angular';
import { Observable } from 'rxjs/Observable';
import { HTTP, HTTPResponse } from '@ionic-native/http';
import 'rxjs/add/operator/map';
import 'rxjs/add/observable/throw';
import 'rxjs/add/observable/defer';
import 'rxjs/add/observable/fromPromise';

@Injectable()
export class HttpService {

  constructor(private platform: Platform, private cordovaHttp: HTTP) {
  }

  request<T>(method: 'GET' | 'POST' | 'DELETE', url: string, options: {
    body?: any;
    params: Map<any, any>;
    headers?: Headers
  }): Observable<HttpServiceResponse<T | any>> {
    const urlWithParams = this.getUrlWithParams(url, options.params);
    let obs: Observable<any>;

    if (this.platform.is('cordova')) {
      obs = this.cordovaRequest<T>(method, urlWithParams, options);
    } else {
      obs = this.browserRequest<T>(method, urlWithParams, options);
    }

    return obs;
  }

  get<T>(url: string, options?: {
    headers?: Headers;
    params?: Map<any, any>;
  }): Observable<HttpServiceResponse<T | any> | T | any> {
    let obs = this.request<T>('GET', url, {
      headers: options ? options.headers : null,
      params: options ? options.params : null
    });

    return obs.map(res => this.handleReponse(res));
  }

  post<T>(url: string, body: any, options?: {
    headers?: Headers;
    params?: Map<any, any>;
    responseType?: 'json' | 'text';
    getRawResponse?: boolean;
  }): Observable<HttpServiceResponse<T | any> | T | any> {
    let obs = this.request<T>('POST', url, {
      body: body,
      headers: options ? options.headers : null,
      params: options ? options.params : null
    });

    // if (options && options.getRawResponse) {
    //   return obs;
    // } else {
    //   return obs.map(res => this.handleReponse(res));
    // }

    return obs.map(res => this.handleReponse(res));
  }

  delete<T>(url: string, body: any, options?: {
    headers?: Headers;
    params?: Map<any, any>;
    responseType?: 'json' | 'text';
    getRawResponse?: boolean;
  }): Observable<HttpServiceResponse<T | any> | T | any> {
    let obs = this.request<T>('DELETE', url, {
      body: body,
      headers: options ? options.headers : null,
      params: options ? options.params : null
    });

    if (options && options.getRawResponse) {
      return obs;
    } else {
      return obs.map(res => this.handleReponse(res));
    }
  }

  private handleReponse<T>(response: HttpServiceResponse<T>): Observable<any> | T {
    if (!response.ok) {
      throw Observable.throw(response);
    }

    return response.data
  }

  private getUrlWithParams(url, params?: Map<any, any>) {
    let queryStrings = [];

    if (params) {
      params.forEach((value, key) => {
        if (Array.isArray(value)) {
          value.forEach(v => {
            queryStrings.push(standardEncoding(key) + '=' + standardEncoding(v));
          })
        } else {
          queryStrings.push(standardEncoding(key) + '=' + standardEncoding(value));
        }
      })
    }
    if (queryStrings.length === 0) {
      return url;
    }
    // Does the URL already have query parameters? Look for '?'.
    const qIdx = url.indexOf('?');
    // There are 3 cases to handle:
    // 1) No existing parameters -> append '?' followed by params.
    // 2) '?' exists and is followed by existing query string ->
    //    append '&' followed by params.
    // 3) '?' exists at the end of the url -> append params directly.
    // This basically amounts to determining the character, if any, with
    // which to join the URL and parameters.
    const sep: string = qIdx === -1 ? '?' : (qIdx < url.length - 1 ? '&' : '');

    return url + sep + queryStrings.join('&');

  }

  private browserRequest<T>(method: 'GET' | 'POST' | 'DELETE', url: string, options: {
    body?: any;
    headers?: Headers;
  }): Observable<HttpServiceResponse<T>> {

    const responseType = 'json';

    return Observable.defer(() => {
      return Observable.fromPromise(
        fetch(url, {
          method: method,
          body: options.body ? JSON.stringify(options.body) : null,
          headers: options.headers || new Headers(),
        })
          .then(
            (response: Response) => {
              const httpResponse: HttpServiceResponse<T> = {
                ok: response.ok,
                status: response.status,
                data: null
              };
              if (!response.ok) {
                httpResponse.errorMessage = 'Error ' + response.status + ' on calling ' + method + ' ' + url;
                return httpResponse;
              }

              const contentType = response.headers.get("content-type");
              if (contentType && contentType.includes("application/json")) {
                return response.json().then(json => {
                  httpResponse.data = json;
                  return httpResponse;
                });
              } else {
                return response.text().then(text => {
                  httpResponse.data = responseType === 'json' ? JSON.parse(text) : text;
                  return httpResponse;
                });
              }

            },
            (err: TypeError) => {
              return <HttpServiceResponse<T>>{
                ok: false,
                status: null,
                data: null,
                errorMessage: err.message
              };
            }
          )
      );
    });
  }

  private cordovaRequest<T>(method: 'GET' | 'POST' | 'DELETE', url: string, options: {
    body?: any;
    headers?: Headers;
  }): Observable<HttpServiceResponse<T>> {
    const responseType = 'json';

    let headers = {};

    if (options.headers) {
      options.headers.forEach((value, key) => {
        headers[key] = value;
      })
    }
    this.cordovaHttp.setDataSerializer('json');

    let promise;

    if (method === 'GET') {
      promise = this.cordovaHttp.get(url, {}, headers);
    } else if (method === 'POST') {
      promise = this.cordovaHttp.post(url, options.body, headers);
    } else if (method === 'DELETE') {
      promise = this.cordovaHttp.delete(url, options.body, headers);
    }

    return Observable.defer(() => {
      return Observable.fromPromise(
        promise
          .then(
            (response: HTTPResponse) => {
              const httpResponse: HttpServiceResponse<T> = {
                ok: response.status >= 200 && response.status <= 299,
                status: response.status,
                data: null
              };

              if (httpResponse.ok) {
                httpResponse.data = responseType === 'json' ? JSON.parse(response.data) : response.data;
              } else {
                httpResponse.errorMessage = 'Error ' + response.status + ' on calling ' + method + ' ' + url;
              }

              return httpResponse;
            },
            response => {
              const httpResponse: HttpServiceResponse<T> = {
                ok: response.status >= 200 && response.status <= 299, // Weird isn't it?
                status: response.status,
                data: null
              };

              if (httpResponse.ok) {
                httpResponse.data = responseType === 'json' ? JSON.parse(response.error) : response.error;
              } else {
                httpResponse.errorMessage = response.error;
              }

              return httpResponse;
            }
          )
      )
    });
  }
}

export interface HttpServiceResponse<T> {
  ok: boolean;
  status: number;
  data: T;
  errorMessage?: string;
}

//Get from angular httpClient
function standardEncoding(v: string): string {
  return encodeURIComponent(v)
    .replace(/%40/gi, '@')
    .replace(/%3A/gi, ':')
    .replace(/%24/gi, '$')
    .replace(/%2C/gi, ',')
    .replace(/%3B/gi, ';')
    .replace(/%2B/gi, '+')
    .replace(/%3D/gi, '=')
    .replace(/%3F/gi, '?')
    .replace(/%2F/gi, '/');
}

Btw this code works well in browser… but failed in Ionic App View

Thank you !

Salva


#4

Use console.log() in the .cordovaRequest() to see what’s going on.


#5

Console.log ? But … it will be running in the Ionic View app … sorry I’m new here… how would I check these logs ?


#6

I don’t know if the IonicView support this but you can install cordova console : https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-console/


#7

Ok guys, I found the solution (a few days ago but I forgot to come back here to ‘close’ this subject).

–> I needed to install the cordova-plugin-advanced-http plugin… It worked immediately after this installation :slight_smile:

Thx all

Salvo.