22

I'm building a front-end only basic Weather App using reactjs. For API requests I'm using Fetch API. In my app, I'm getting the current location from a simple API I found and it gives the location as a JSON object. But when I request it through Fetch API, I'm getting this error.

Failed to load http://ip-api.com/json: Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response.

So I searched through and found multiple solutions to fix this.

  1. Enabling CORS in Chrome solves the error but when I deploy the app on heroku, how can I access it through a mobile device without running into the same CORS issue.
  2. I found an proxy API which enables the CORS requests. But as this is a location request, this gives me the location of the proxy server. So it's not a solution.
  3. I've gone through this Stackoverflow question and added the headers to the header in my http request but it doesn't solve the problem. (Still it gives the same error).

So how can I solve the issue permanently ? What's the best solution I can use to solve the CORS issue for http requests in Fetch API ?

Phil
  • 157,677
  • 23
  • 242
  • 245
Thidasa Pankaja
  • 930
  • 8
  • 25
  • 44
  • that server is configured to disallow you from fetching it from a browser (CORS). You can get it all day with cURL. If you can't get them to add the CORS header on their Web server, rethink your idea. – Ronnie Royston Feb 11 '18 at 05:05
  • 1
    Read the error message closely... you appear to be setting `Access-Control-Allow-Origin` as a **request** header. This is a **response** header only, it must come from the server and has no place in your request. This would have been trivially easy to point out if you included _any_ code in your question – Phil Feb 16 '23 at 01:16

3 Answers3

8

To the countless future visitors:

If my original answer doesn't help you, you may have been looking for:


Regarding the issue faced by the OP...

That API appears to be permissive, responding with Access-Control-Allow-Origin:*

I haven't figured out what is causing your problem, but I don't think it is simply the fetch API.

This worked fine for me in both Firefox and Chrome...

fetch('http://ip-api.com/json')
   .then( response => response.json() )
   .then( data => console.log(data) )
Brent Bradburn
  • 51,587
  • 17
  • 154
  • 173
  • I've added the header `Access-Control-Allow-Origin:*` in Fetch API request. But it don't solve the problem. It works only when I enable the CORS in the browser using a plugin. – Thidasa Pankaja Feb 11 '18 at 05:20
  • 2
    I seem to be missing something, but *you* should not be adding `Access-Control-Allow-Origin:*` to your request -- the API server puts that in their response. Which they do, according to my test. – Brent Bradburn Feb 11 '18 at 05:22
  • 1
    After reading about adding headers and many things I've added headers in my request. And I replaced the whole fetch API request with what you mentioned and it works a charm. Thanks a lot – Thidasa Pankaja Feb 11 '18 at 05:33
  • 4
    It worked for me with this args: `fetch('http://ip-api.com/json', { method: "GET", mode: 'cors', headers: { 'Content-Type': 'application/json',}}).then(response => response.json())` Thanks to Nafiu Lawal – mndv May 10 '21 at 15:01
  • From what I can tell, the default value for [Request.mode](https://developer.mozilla.org/en-US/docs/Web/API/Request/mode) is `cors`. – Brent Bradburn Feb 16 '23 at 00:44
6

if you are making a post, put or patch request, you have to stringify your data with body: JSON.stringify(data)

fetch(URL, 
        {
            method: "POST", 
            body: JSON.stringify(data),
            mode: 'cors',
            headers: {
                'Content-Type': 'application/json',
            }
        }
    ).then(response => response.json())
    .then(data => {
        ....
    })
    .catch((err) => {
        ....
        })
    });
Nafiu Lawal
  • 447
  • 1
  • 7
  • 16
1

You should use the proxy solution, but pass it the IP of the client instead of the proxy. Here is an example URL format for the API you specified, using the IP of WikiMedia:

http://ip-api.com/json/208.80.152.201

Tallboy
  • 12,847
  • 13
  • 82
  • 173
  • This works. But hard-coding IP as this will be a problem when I log in from a different IP right ? So how can I get the client IP as the IP is in the response object. So how can I get the IP before send the request (to attach in the request as you've mentioned) ? – Thidasa Pankaja Feb 11 '18 at 04:47
  • To make a proxy you need server side code (like PHP, ruby, etc). You would simply look at the IP of the incoming request, use that in the URL, get the response (in PHP still), take THAT response and then send it to the actual browser (so the browser is not the one making the request). That will bypass the CORS restrictions because the file is placed on your own domain, and CORS no longer applies. – Tallboy Feb 11 '18 at 04:54
  • 1
    You won't be able to do this in JS alone unless you use JSONP, it appears they support it: http://ip-api.com/docs/api:json – Tallboy Feb 11 '18 at 04:55
  • Thanks. I'll look into that. btw, seems like it was a issue with headers in my request. Fixed it by replacing a simple code which the other guy has mentioned and it works like charm – Thidasa Pankaja Feb 11 '18 at 05:35