Angular 6 HttpClient - Issues with CORS

Viewed 15201

My Nodejs restful service has the following endpoint http://localhost:3000/api/countries. I am using this middleware https://github.com/expressjs/cors. I have cors enabled thus:-

const cors = require('cors');
app.use(cors({
  'allowedHeaders': ['sessionId', 'Content-Type'],
  'exposedHeaders': ['sessionId'],
  'origin': '*',
  'methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
  'preflightContinue': false
}));

I have the following code in my Angular 6 app hosted at http://localhost:4200

   import { HttpClient, HttpHeaders } from '@angular/common/http';

   httpClient: HttpClient;

   getCountries(): Observable<any> {
     const url = 'http://localhost:3000/api/countries';
     const httpOptions = {
      headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Access-Control-Allow-Origin':'*'
      })
     };
     return this.httpClient.get(url, httpOptions).pipe(
        map((result: any) => {
            return result;
        })
     );
   }

I have the following code in my React App at http://localhost:3001

getCountries() {
    const url = 'http://localhost:3000/api/countries';
    const init = {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json'
      }
   };

   try {
    const response = await fetch(url, init);
    const json = await response.json();
    return json
   };
 }

My react code works perfectly giving the desired response, but the Angular 6 gives the following error:-

Access to XMLHttpRequest at 'http://localhost:3000/api/countries' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.

What am I doing wrong in my angular 6 code?

Please note that I have seen answers to similar questions suggesting using a json file (proxy.conf.json) to act as a proxy server or install a chrome extension. These are not options for me.

Thanks in advance of your helpful responses.

3 Answers

You can use this if you want a quick temporary solution.

const url = 'https://cors-anywhere.herokuapp.com/http://localhost:3000/api/countries';

The CORS is mostly a backend issue. You can solve it on Node.js with a code such as:

var express = require('express');
var app = express();
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

But if you want to solve it in frontend, you may use this kind of code in Angular. Put this code into a proxy.conf.json (but beware, a trailing slash is enough to make it not to work):

{
  "/api/*": {            <-- you may change this for /api/country
      "target": "http://localhost:3000",
      "secure": false,
      "logLevel": "debug",
      "changeOrigin": true
  }
}

The following in package.json:

"scripts": {
    "ng": "ng",
    "start": "ng serve --proxy-config proxy.conf.json",
    ...
}

And add the proxy config in angular.json:

"serve": {
  "builder": "@angular-devkit/build-angular:dev-server",
  "options": {
    "browserTarget": "event:build",
    "proxyConfig": "proxy.conf.json"  <-- this line
  },...

Start it with npm start.

It should work in your case, but in other cases (not in prod of course), I find it easier to use temporarily an extension for Chrome or Firefox. Also I found that because of some restriction it may not work in Chromium and Chrome Canary.

Additionally with React the following code may help:

const proxy = require("http-proxy-middleware");

module.exports = app => {
  app.use(
    "/api",   <-- here again, make sure it fits your needs or it won't work
    proxy({
      target: "http://localhost:3000",
      changeOrigin: true
    })
  );
};

Try using ng serve --port 3000 . The CORS is mostly backend issue. Since react starts it's server in localhost:3000 you were able to consume it, since angular starts in localhost:4200 you got the cors issue.

Related