46

I am trying to make an API call through Axios in my React Application. However, I am getting this CORS issue on my browser. I am wondering if i can resolve this issue from a client side as i dont have any access to the API internally. Attached is my code.

const response = axios({
  method: "post",
  dataType: "jsonp",
  url: "https://awww.api.com",
  data: {
    appToken: "",
    request: {
      applicationName: "ddfdf",
      userName: "jaime@dfd.com",
      password: "dfd",
      seasonIds: [1521ddfdfd5da02],
    },
  },
});

return {
  type: SHARE_REVIEW,
  payload: "response",
};

Attached is my WebPack.config.js

module.exports = {
  entry: ["./src/index.js"],
  output: {
    path: __dirname,
    publicPath: "/",
    filename: "bundle.js",
  },
  module: {
    loaders: [
      {
        exclude: /node_modules/,
        loader: "babel",
        query: {
          presets: ["react", "es2015", "stage-1"],
        },
      },
      { test: /\.json$/, loader: "json-loader" },
    ],
  },
  resolve: {
    extensions: ["", ".js", ".jsx"],
  },
  devServer: {
    historyApiFallback: true,
    contentBase: "./",
  },
  node: {
    dns: "mock",
    net: "mock",
  },
};
Ahmed
  • 2,966
  • 7
  • 42
  • 69
mohan babu
  • 1,388
  • 2
  • 17
  • 35
  • 10
    the server should send appropriate headers if it allows you to use it's resources ... so, fix server side, only, client can't bypass CORS, as that would make CORS irrelevant – Jaromanda X Apr 18 '17 at 02:02

12 Answers12

63

the simplest way what I found from a tutorial of "TraversyMedia" is that just use https://cors-anywhere.herokuapp.com in 'axios' or 'fetch' api

https://cors-anywhere.herokuapp.com/{type_your_url_here} 

e.g.

axios.get(`https://cors-anywhere.herokuapp.com/https://www.api.com/`)

and in your case edit url as

url: 'https://cors-anywhere.herokuapp.com/https://www.api.com',
Manoj Sharma
  • 1,068
  • 2
  • 11
  • 17
  • 2
    holy #%$ this worked! my days are saved, can you explain what this is doing? – some_groceries Jan 18 '19 at 14:32
  • 3
    CORS-Anywhere HerokuApp provides a proxy that passes on our request along with its headers. you can learn more on https://cors-anywhere.herokuapp.com and for more explanation visit medium's post- https://medium.com/netscape/hacking-it-out-when-cors-wont-let-you-be-great-35f6206cc646 – Manoj Sharma Jan 19 '19 at 14:31
  • 93
    Please note that this results in all your API requests passing through a third party application which is definitely not a good security practice. – Manish Aug 20 '19 at 04:37
  • 7
    Herokuapp "Cors Anywhere" is a demo and it is very slow, so it cannot be used on a production live application. – Gianpaolo Papa Aug 10 '20 at 17:43
  • 2
    You never want to do this in a production application. As @Manish pointed out, the security implications are obvious. Beyond this, you are limiting the performance of your application to whatever this third party is able to handle. Your application will also go down whenever it goes down, and fail whenever (if) the url changes, etc. Please don't do this. – java-addict301 Jul 08 '21 at 17:02
14

The ideal way would be to add CORS support to your server.

You could also try using a separate jsonp module. As far as I know axios does not support jsonp. So I am not sure if the method you are using would qualify as a valid jsonp request.

There is another hackish work around for the CORS problem. You will have to deploy your code with an nginx server serving as a proxy for both your server and your client. The thing that will do the trick us the proxy_pass directive. Configure your nginx server in such a way that the location block handling your particular request will proxy_pass or redirect your request to your actual server. CORS problems usually occur because of change in the website domain. When you have a singly proxy serving as the face of you client and you server, the browser is fooled into thinking that the server and client reside in the same domain. Ergo no CORS.

Consider this example.

Your server is my-server.com and your client is my-client.com Configure nginx as follows:

// nginx.conf

upstream server {
    server my-server.com;
}

upstream client {
    server my-client.com;
}

server {
    listen 80;

    server_name my-website.com;
    access_log /path/to/access/log/access.log;
    error_log /path/to/error/log/error.log;

    location / {
        proxy_pass http://client;
    }

    location ~ /server/(?<section>.*) {
        rewrite ^/server/(.*)$ /$1 break;
        proxy_pass http://server;
    }
}

Here my-website.com will be the resultant name of the website where the code will be accessible (name of the proxy website). Once nginx is configured this way. You will need to modify the requests such that:

  • All API calls change from my-server.com/<API-path> to my-website.com/server/<API-path>

In case you are not familiar with nginx I would advise you to go through the documentation.

To explain what is happening in the configuration above in brief:

  • The upstreams define the actual servers to whom the requests will be redirected
  • The server block is used to define the actual behaviour of the nginx server.
  • In case there are multiple server blocks the server_name is used to identify the block which will be used to handle the current request.
  • The error_log and access_log directives are used to define the locations of the log files (used for debugging)
  • The location blocks define the handling of different types of requests:
    1. The first location block handles all requests starting with / all these requests are redirected to the client
    2. The second location block handles all requests starting with /server/<API-path>. We will be redirecting all such requests to the server.

Note: /server here is being used to distinguish the client side requests from the server side requests. Since the domain is the same there is no other way of distinguishing requests. Keep in mind there is no such convention that compels you to add /server in all such use cases. It can be changed to any other string eg. /my-server/<API-path>, /abc/<API-path>, etc.

Even though this technique should do the trick, I would highly advise you to add CORS support to the server as this is the ideal way situations like these should be handled.

If you wish to avoid doing all this while developing you could for this chrome extension. It should allow you to perform cross domain requests during development.

Nahush Farkande
  • 5,290
  • 3
  • 25
  • 35
12

Temporary solve this issue by a chrome plugin called CORS. Btw backend server have to send proper header to front end requests.

Sajed
  • 445
  • 1
  • 8
  • 19
  • 2
    This worked like a charm. Really helpful if you just want to test and get something up and running. I used the Moesif Origin & CORS Changer plugin. Just turn it on and it works! – EFreak May 16 '18 at 11:38
8

You can have your React development server proxy your requests to that server. Simply send your requests to your local server like this: url: "/" And add the following line to your package.json file

"proxy": "https://awww.api.com"

Though if you are sending CORS requests to multiple sources, you'll have to manually configure the proxy yourself This link will help you set that up Create React App Proxying API requests

Younes Henni
  • 178
  • 1
  • 5
  • More elaborated similar answer can be found [here](https://stackoverflow.com/a/50661999/3002584). – OfirD Sep 23 '21 at 14:01
7

Another way besides @Nahush's answer, if you are already using Express framework in the project then you can avoid using Nginx for reverse-proxy.

A simpler way is to use express-http-proxy

  1. run npm run build to create the bundle.

    var proxy = require('express-http-proxy');
    
    var app = require('express')();
    
    //define the path of build
    
    var staticFilesPath = path.resolve(__dirname, '..', 'build');
    
    app.use(express.static(staticFilesPath));
    
    app.use('/api/api-server', proxy('www.api-server.com'));
    

Use "/api/api-server" from react code to call the API.

So, that browser will send request to the same host which will be internally redirecting the request to another server and the browser will feel that It is coming from the same origin ;)

Rvy Pandey
  • 1,654
  • 3
  • 16
  • 22
Niraj
  • 477
  • 6
  • 16
  • Say If i want to host this full app (with front end react and bundled build html as backend ) to GitHub pages it would be causing a problem right? – Aswath Dec 21 '22 at 07:45
3

You can set up a express proxy server using http-proxy-middleware to bypass CORS:

const express = require('express');
const proxy = require('http-proxy-middleware');
const path = require('path');
const port = process.env.PORT || 8080;
const app = express();

app.use(express.static(__dirname));
app.use('/proxy', proxy({
    pathRewrite: {
       '^/proxy/': '/'
    },
    target: 'https://server.com',
    secure: false
}));

app.get('*', (req, res) => {
   res.sendFile(path.resolve(__dirname, 'index.html'));
});

app.listen(port);
console.log('Server started');

From your react app all requests should be sent to /proxy endpoint and they will be redirected to the intended server.

const URL = `/proxy/${PATH}`;
return axios.get(URL);
Harshad Ranganathan
  • 1,820
  • 16
  • 31
  • This is interesting. So this proxy server would need to be run within the front-end React app? – MarvinLazer Mar 01 '21 at 03:13
  • 2
    @MarvinLazer The proxy server needs to run within the same server that serves your React App. You can check this repo for working example - https://github.com/HarshadRanganathan/gnib-visa-app. This repo in dev mode uses express proxy server and in production mode uses nginx proxy server which also serves the static react files. – Harshad Ranganathan Mar 01 '21 at 15:49
1

As @Nahush already pointed out, this is actually a server issue and not something that should be handled on the client side. The server is supposed to add the headers for Access-Control-Allow-Origin: Reference - https://www.w3.org/wiki/CORS_Enabled#How_can_I_participate.3F

Here, I am just adding an easier way to do this on the server side if your server uses express framework. Using the express CORS Middleware is a 2 line code solution for this.

install using -

npm install -S cors

Add the following code to your backend app.

import cors from 'cors';
app.use(cors());

And done.

Karan Sharma
  • 473
  • 5
  • 8
1

you must be missing Cors support on your server side code. In Asp.net core you can do it following way. Add the following call in public void ConfigureServices(IServiceCollection services) in Startup.cs file.

public void ConfigureServices(IServiceCollection services)
{
     app.UseCors(options => 
                options.WithOrigins("http://localhost:3000").AllowAnyHeader().AllowAnyMethod());
}
        
Captain_Levi
  • 87
  • 1
  • 5
1

I had the issue and I was in a dev environment (localhost) so my client and server origins where different...

  • so finally I overcame the problem by writing a simple custom proxy server that runs on localhost, (because I didn't had access to the server code, and I needed to allow cors from the responding origin)

Simple proxy server that runs on localhost:3001:

const express = require("express");
const { createProxyMiddleware } = require("http-proxy-middleware");
var cors = require("cors");

const app = express();
const corsOptions = {
  //   origin: ["http://localhost:3000"],
  origin: true,
  credentials: true,
};
app.use(cors(corsOptions));

const proxyMiddleware = createProxyMiddleware("/", {
  target: "https://....api origin.....com",
  changeOrigin: true,
});

app.use(proxyMiddleware);

app.listen(3001, () => {
  console.log("proxy is listening on port 3001");
});
  • note that my react app is running on port 3000 and my proxy server is on port 3001
  • because we're using credentials in our request we need to also set origin to our app's origin to our white list, otherwise cors sets "Access-Control-Allow-Origin" to "*" which causes in-browser security error.

react sample login post request through my proxy:

      axios.post("http://localhost:3001/Login", dataToPost, { withCredentials: true })
      .then((res) => {
        if (res.status === 200) {
          //all cookies are set in you're browser
          console.log(res);
        }
      })
      .catch((err) => {
        console.log(err);
      });
BOOMHUNK
  • 356
  • 3
  • 6
1

If you are trying to do something like fetch a third-party API, and you're getting a CORS error from the client side, you can try to do this using the Allow CORS: Access-Control-Allow-Origin extension.

For Chrome | For Mozilla

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/late-answers/31647548) – Tom May 05 '22 at 10:09
  • But in this particular case, only using this extension (allow-cors) can be a solution, there's no need for understand the deep part of how the extension works or else, because we have no code involved. But I'll edit with the name of the extension. – Matheus Alves May 06 '22 at 12:38
  • You really need to highlight that this is only available as a workaround. Admittedly, the question only asks for how they can fix it on _their_ browser, but the context implies they are building a web app and an extension isn't a viable option since you're expecting all users to have that extension installed – Tom May 10 '22 at 08:46
0

I did use 2 solutions to dealing with it:

  1. Using http-proxy-middleware. However, please do following below steps on video, instead of read me of library, https://youtu.be/4B5WgTiKIOY . (I did mention the weakness if you use this solution also)
  2. Use Firebase functions to create middleware, not too complicated. I will update detail then here also.

Please let me know if you have any question.

Jenny Tran
  • 553
  • 4
  • 10
0

NOTE: This is a answer for a specific requirement.
If there is an external API (like microsoft's signed blob storage links) which is accepting the request but doesn't have CORS properties explicitly set.
For these types of requests you can apply a hack to download files e.g. excel, images.
All you have to do is create i.e. img, iframe, tags which will show/download the given resource without making an external request that can be blocked by CORS.

const container = document.createElement('iframe');
container.setAttribute('src', response);
document.body.appendChild(container);

Don't forget to delete the iframe at the end as they are gonna pile up. e.g:

setTimeout(() => document.body.removeChild(container), IFRAME_TTL);

This is a very specific use-case don't know if can be applied to other ones. Hope it helps.