adrisons
adrisons

Reputation: 3723

Error when GET HTTPS from REST API in Angular

I have an Angular app running which uses an external api to get countries ISOs. This API uses https and it's giving me an error.

The thing is: when I use a proxy in my angular local environment, mapping /iso-api/ to the real url it works ok.

"/iso-api/*": {
    "target": "https://www...",
    "pathRewrite": { "^/iso-api": "" },
    "secure": false,
    "changeOrigin": true,
    "logLevel": "debug"
}

But I want this to work in production, so I want to use the real url.

In my server I am returning the Access-Control-Allow-Origin: * header already.

I've tried to run the angular server with ssl (as the external api uses https), but I receive the same error.

I know a solution would be to implement the proxy in the server, but I believe this should not be done and there may be a way to retrieve this data from the frontend. Help please.

Response

This is the network error in Chrome: browser network tab

In Firefox, the request ends with 200 OK and returns data, but CORS error is thrown and I cannot access the data from the app: CORS header 'Access-Control-Allow-Origin' missing

General

Request URL: https://www...
Referrer Policy: no-referrer-when-downgrade

Request headers

:method: GET
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: es-ES,es;q=0.9,en;q=0.8
origin: http://localhost:4200
referer: http://localhost:4200/app/login
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site

Response headers

accept-ranges: bytes
cache-control: max-age=0
content-encoding: gzip
content-language: en-US
content-length: 68356
content-type: application/json
date: Mon, 27 Apr 2020 14:49:30 GMT
expires: Mon, 27 Apr 2020 14:49:30 GMT
referrer-policy: strict-origin-when-cross-origin
server-timing: cdn-cache; desc=HIT
server-timing: edge; dur=1
server-timing: ACTT;dur=0,ACRTT;dur=88
set-cookie: ... expires=Mon, 27 Apr 2020 16:49:30 GMT; max-age=7200; path=/; domain=...; HttpOnly
set-cookie: ... Domain=...; Path=/; Expires=Mon, 27 Apr 2020 18:49:30 GMT; Max-Age=14400; HttpOnly
set-cookie: ... Domain=...; Path=/; Expires=Tue, 27 Apr 2021 14:49:30 GMT; Max-Age=31536000; Secure
status: 200
vary: Accept-Encoding

UPDATE

Angular service code

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

...

constructor(
    private _http: HttpClient,
    private _errorUtil: ErrorUtilService,
    private _converter: StoreConverter
  ) {}

...
  getCountries(): Observable<CountryWithLanguages[]> {
    return this._http.get<GetStoresResponse>(API.storeUrl).pipe(
      catchError(this._errorUtil.handle),
      map(result => result.stores),
      switchMap(stores => stores),
      filter(this._isActiveStore),
      map(store => this._converter.toView(store)),
      toArray()
    );
  }

To serve the app I use angular dev server, I do not add the 'Access-Control-Allow-Origin' header manually but, in the browser, I see that it is being added.

Chrome Network tab

angular.json

"serve": {
          "builder": "@angular-devkit/build-angular:dev-server",
          "options": {
            "browserTarget": "push-web-app:build",
            "proxyConfig": "src/proxy-local.conf.json"
          },
         }

Upvotes: 2

Views: 14477

Answers (4)

Jakub Nowak
Jakub Nowak

Reputation: 316

You can't request a resource from another domain. This would be a security hole. You can read more here: Same-origin policy

Sending Access-Control-Allow-Origin: * from your server won't give you access to the aforementioned API. The provider of this API needs to give you permission to access the API, you can't give yourself this permission.

The error you posted states that the Access-Control-Allow-Origin header is missing. It means that the API isn't sending this header.

There might be two reasons why this API isn't sending Access-Control-Allow-Origin header.

  1. A misconfiguration on the side of this API. In this case you have to ask the provider of this API to fix this issue.
  2. The API provider is restricting access to the API on purpose. In this case you have to ask the provider of this API to give you access from your domain.

You can also proxy the request through your server. The core difference when using proxy is that your server reads the resource from the API and not the client browser. See David's response on how to configure proxy with nginx.

Upvotes: 2

David
David

Reputation: 34435

You cannot bypass CORS browser side. If you are not able to modify the server side, your only solution is to use a proxy.

For development purposes, you can use angular's built-in proxy server, but not for production.

Here is a basic nginx config to do this

server {
    listen          80;
    server_name     yourdomain.com; #domain where your angular code is deployed

    location /iso-api{

        RewriteRule                     ^/iso-api/(.*)$ /$1 break;
        proxy_pass                      https://thirdpartyapidomain.com; #url of the API you are trying to access
    }

    location
    {
        #Your normal angular location
        #try_files ...
    }
}

This will redirects requests like

http://yourdomain.com/iso-api/countriesList to https://thirdpartyapidomain.com/countriesList;

Since now client and server API calls are on the same domain, you should not have CORS issues

Upvotes: 1

kflo411
kflo411

Reputation: 124

Try the .get call with option withCredentials: true:

return this._http.get<GetStoresResponse>(API.storeUrl, { withCredentials: true }).pipe();

...and/or making sure your browsers are up to date.

Upvotes: 0

Luciano
Luciano

Reputation: 475

Use this site to resolve the CORS error: https://cors-anywhere.herokuapp.com/

Use Exemple https://cors-anywhere.herokuapp.com/https://freegeoip.app/json

this._http.get('https://cors-anywhere.herokuapp.com/https://freegeoip.app/json')

It's just a workaround but it works. Use it even just to understand if the error is related to CORS or something else.

Upvotes: 0

Related Questions