2

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"
          },
         }
18
  • So you are calling your production API from your localhost server? It's a bit weird to have a err_failed error but still have response headers.. you have no other errors in the console? Commented Apr 29, 2020 at 19:01
  • So potentially dumb ask but have you tried using fetch or ajax? Just to see if you can pinpoint the exact location of the issue? Commented Apr 30, 2020 at 3:21
  • It's an open API, not a production app that I manage, it works when accessing to the url from the browser. No errors in the console, just that message in the network tab... I've tried using fetch but the same happens. I think the problem is not with the http get request, but with the browser restricting cors Commented Apr 30, 2020 at 11:33
  • 2
    You might want to try using Firefox devtools to inspect the request — because there are unfortunately a number of different cases in which Chrome devtools is no longer exposing certain request and response details. See stackoverflow.com/q/57410051/441757 for example. Commented May 2, 2020 at 2:27
  • 1
    So the answer to your question is that you need to set up your own proxy in your production environment on your remote server. This is the only way to get around CORS if you do not own the API server. What kind of webserver are you using? Nginx? Commented May 6, 2020 at 9:40

4 Answers 4

2
+50

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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

1 Comment

To be exact you should say "You cannot bypass same-origin policy browser side" instead of "You cannot bypass CORS browser side". CORS is as method of relaxing same-origin policy.
0

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.

1 Comment

Thanks, but I need a strong solution. I am trying to find a solution in the frontend. As I wrote in the question: 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.
0

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.

2 Comments

The request does not need authorization. I've tried it anyway and it didn't work.
I figured, but there's been some precedent in other cases where a required cert was passed via withCredentials -- was worth a shot. Good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.