Using XMLHttpRequest object.

In the angular app, following code snippet was used to access resource from j2EE app.

var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { console.log(xhttp.responseText); } }; xhttp.open("GET", "http://localhost:8081/e2e/api/", true); xhttp.send();

The java app has the following code in the doGet( ) method of the servlet.

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("{\"id\" : \"1\" , \"value\" : \"AwesomeAPI\"}"); }

The above angular code when triggered hit the server at localhost:8081 and in the network tab of the chrome developer tool we observe the following request and response:

Request-Response when CORS not enabled.

Important point to note here are the Request Headers.

Host refers to the server where API’s are hosted and Origin refers to the server from where client is served.

Although the call reaches API and response contains the expected data with status 200 OK, still the browser will not allow the response data to reach the caller code. Browser will crib stating :

Failed to load http://localhost:8081/e2e/api/: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:4200' is therefore not allowed access.

To fix this

Add ‘Access-Control-Allow-Origin’ header in the response with appropriate value.

With this change API code will be :

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.addHeader("Access-Control-Allow-Origin", "*"); response.getWriter().println("{\"id\" : \"1\" , \"value\" : \"AwesomeAPI\"}"); }

Here * means allow access to this API from any origin. This can be specific origin value also but for now we are going ahead with *.

Again fire the same API from client at localhost:4200, following request response is observed :

Request-Response when CORS is enabled

Since the response is containing Access-Control-Allow-Origin: *, the browser honors the response and allows the code to read the same. See Console.

2. Using HttpClinet library in Angular

Instead of using plain XMLHttpRequest API we can use HttpClient library in Angular application. This API returns RxJs Observable.

Code :

Since HttpClient internally using XMLHttpRequest web APIs, we get the same behavior when CORS is enabled/disabled.

3. When Server support for CORS is not available.

As seen before, CORS work when server adds the required ‘Access-Control-Allow-Origin’ header in the response. In cases when we don’t have control over server response, we need to have a proxy to access Cross Origin Resources.

3.1 Angular support

Angular application development recommends Node.js way of development. That means we install angular CLI as node module and dependencies are maintained via package.json.

Node server is used to serve the client side files including angular framework.

By default node server starts at http://localhost:4200.

In order to create a proxy which can redirect calls to other origin (to support CORS) webpack (module bundler used by Angular) dev server provides support.

Details about this can be read in this article :

https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/proxy.md

Basically all the CORS calls that we want to make from angular client will go via node server running at http://localhost:4200 and the server will proxify the calls and return the response.

To start with :

3.1.1 API at http://localhost:8081/e2e/api/ does not support CORS and does not add ‘Access-Control-Allow-Origin’ in the response header.

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().println("{\"id\" : \"1\" , \"value\" : \"AwesomeAPI\"}"); }

3.1.2 Client code

The server responds with 404 as the API is not served via http://localhost:4200

3.1.3 Define a file called proxy.conf.json and place it next to package.json

{

"/e2e/api": {

"target": "http://localhost:8081",

"secure": false,

"changeOrigin": true

}

}

3.1.4 Start the server with proxy config option

ng serve --proxy-config proxy.conf.json

Now we get a response. Observe the request headers. Origin is not available and the API is going via our proxy at http://localhost:4200

This is actually a generic solution to have a proxy for API’s when server side support for CORS is not available.

4. Achieving CORS when proxy can not be setup. (only during development/testing phase — Not productive scenario)

Suppose we have a scenario where we cannot set up a server proxy and would like to only check whether an API is serving our purpose or not. Whether an API is sending correct data or not, then during development phase we can make use of browser plugins which add ‘Access-Control-Allow-Origin’ to all the responses.

Just search for CORS plugin for your browser.

I have added https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en for testing purpose.

I have reset my angular code, such that it is directly making call to http://localhost:8081/e2e/api

the api does not send ‘Access-Control-Allow-Origin’ in response, so the call fails.

Added plug-in gives the following options in the chrome :

As the settings show I have given http://localhost:8081/e2e/api/* as URL pattern to intercept.

Now when a call is made from client at http://localhost:4200 we get proper response as in: