0

I have an Angular app that makes REST calls to a "third party" REST-service. Think of this service as something like www.someothercompany/restapi/MyObject/1.

When I run my app locally (via ng serve) my app can make calls to this service.

When I create my container locally, and run my container locally, my app is not working with the service.

So I tried debugging it, I created a terminal window on the local running container (I documented my "add curl" in Can't run Curl command inside my Docker Container)

curl -v --header "Accept: application/json" www.someothercompany/restapi/MyObject/1

and this call works.

My Angular code looks like this:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { environment } from  '../../../../environments/environment';
import { MyObjectInfoRequest,MyObjectInfoResponse } from "./myObject-info.model";

@Injectable({ providedIn: 'root' })
export class MyObjectInfoService {


    constructor(private http: HttpClient) {
    }

    getMyObject(myObjectRequest: MyObjectInfoRequest) {
        let headers = new HttpHeaders();
        headers.append('Accept','application/json');
        return this.http.get<MyObjectInfoResponse>(
            environment.myObjectInfoUrl+`?`,
            {
                headers:headers,
                params: { _id: myObjectRequest.id }
            })
            .pipe(map(myObjectInfoResponse => {
                return myObjectInfoResponse;
            }));
    }
}

the http.get looks like my curl command.

Does anybody see anything I'm not doing correctly?

APPEND:

My Dockerfile (constructed mainly from this example : How to create a Docker container of an AngularJS app?)

FROM node:latest as my-thing-builder
LABEL author="ME"
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install
COPY . .
RUN npm run build -- --configuration=dev

FROM nginx:alpine
#RUN apk add --no-cache curl
# Install prerequisites
#RUN apt-get update && apt-get install -y curl

VOLUME /tmp/cache/nginx
# support running as arbitrary user which belogs to the root group
RUN chmod -R 777 /var/cache/nginx /var/run /var/log/nginx /var/cache/nginx/
# users are not allowed to listen on priviliged ports
RUN sed -i.bak 's/listen\(.*\)80;/listen 8081;/' /etc/nginx/conf.d/default.conf
EXPOSE 8081
# comment user directive as master process is run as user in OpenShift anyhow
RUN sed -i.bak 's/^user/#user/' /etc/nginx/nginx.conf

COPY --from=my-thing-builder /app/dist /usr/share/nginx/html
COPY ./scaffolding/nginx/nginx.dev /etc/nginx/conf.d/default.conf

CMD ["nginx", "-g","daemon off;"]



#USER 1001
# docker build -t my-thing:dev -f ./scaffolding/docker/my.dockerfile .
# docker run -d -p 8899:8080 my-thing:dev 
# the docker run above will allow local http://localhost:8899/

APPEND

Ok....I did get some basic-basic errorHandling in.

My revised version.

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { map, catchError } from 'rxjs/operators';
import { Observable, throwError } from 'rxjs';
import { environment } from  '../../../../environments/environment';
import { MyObjectInfoRequest,MyObjectInfoResponse } from "./myObject-info.model";

@Injectable({ providedIn: 'root' })
export class MyObjectInfoService {


    constructor(private http: HttpClient) {
    }

    getMyObject(myObjectRequest: MyObjectInfoRequest) {
        let headers = new HttpHeaders();
        headers.append('Accept','application/json+fhir');
        return this.http.get<MyObjectInfoResponse>(
            environment.myObjectInfoUrl+`?`,
            {
                withCredentials: true,
                headers:headers,
                params: { _id: myObjectRequest.id }
            })
            .pipe(map(myObjectInfoResponse => {
                return myObjectInfoResponse;
            })
            ,
            catchError(err => {
                //console.log(err);
                //alert(err);
                this.handleError(err);
                return throwError(err)
                })            
            );
    }

    private handleError(error: HttpErrorResponse) {
        if (error.error instanceof ErrorEvent) {
          // A client-side or network error occurred. Handle it accordingly.
          //alert('ErrorEvent ' + error.error.message);
          console.error('An error occurred:', error.error.message);
        } else {
          // The backend returned an unsuccessful response code.
          // The response body may contain clues as to what went wrong,
          //alert('Else ' + error.status + ':::' + error.error);
          console.error(
            `Backend returned code ${error.status}, ` +
            `body was: ${error.error}`);
        }
        // return an observable with a user-facing error message
        return throwError(
          'Something bad happened; please try again later.');
      };    
}

==========

Aha!

502

Bad Gateway

nginx/1.15.18

ERROR Object { headers: Object, status: 502, statusText: "Bad Gateway", url: "http://localhost:8899/restapi/MyObject/1", ok: false, name: "HttpErrorResponse", message: "Http failure response for http://localhost:8899/restapi/MyObject/1", error: "<html> <head><title>502 Bad Gateway…" }
granadaCoder
  • 26,328
  • 10
  • 113
  • 146
  • 5
    Could you expand on *"not working"*? Those calls will be made from the *client*, the browser, which is probably not inside the Docker container at all. Is it `ng serve` running in the container, or are you just serving the `ng build` output? Which environment is set? – jonrsharpe Jan 25 '19 at 11:14
  • 1
    You should definitely be catching the error from your http call anyway just as good practice. It would also help us debug your problem, if we could see the error message. I'm also going to be bet it's because angular's http uses a different set of certificates, or perhaps ssl protocol, from your container's native curl command. – Abulafia Jan 25 '19 at 11:51
  • I agree, my description is a little lax. @Abu, yes, I am adding catchError stuff right now. This is an early proof of concept, not a best-practice-production-level app, so I'm adding exception tracking now. – granadaCoder Jan 25 '19 at 13:17
  • More info added to question. But I did finally figure it out. Doh on me for lack of errorHandler. But I'm new to the AngularJS game (C# and Java ... for middle tier WCF and Rest-SERVICES for I guess 8-10 years) – granadaCoder Jan 25 '19 at 15:09

1 Answers1

0

Ok, via the comments, I was able to add better errorHandling (a duh moment, but I'm new to AngularJS ... so bear with me)

While I had an entry in for the reverse proxy setup, it was not engaging.

So it needed some tweaks in the nginx configuration

Something like this: (the original)

 location /restapi {
        proxy_pass https://www.someothercompany;
    }

The resolution (with some help from co-workers) was better https setup:

 location /restapi {
    proxy_ssl_server_name on;
    proxy_pass https://www.someothercompany;
    proxy_ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
    proxy_ssl_ciphers             HIGH:!aNULL:!MD5;
    proxy_ssl_session_reuse on;
}

But it DID behave differently from local running and versus running in the container. Which of course nginx was the "difference" between the two.

Here is a weird caveat I didn't originally report. It WAS working in a container deployed to Open-Shift, but it was NOT working in a local-docker-run. do WHAT???

I feel a little silly.

But at the same time, I'm not going to delete the question because I think if could help someone in the future.

granadaCoder
  • 26,328
  • 10
  • 113
  • 146