Search code examples
node.jsreactjscorsrender.com

Getting No Access-Control-Allow-Origin cors error but the header is set and works fine in local environment but will not work live on render.com


Summary: I am using cors npm on nodejs backend and am able ON LOCAL MACHINE to successfully make requests from frontend on a port separate from backend. IN PRODUCTION I get a cors error saying no Access-Control-Allow-Origin is set. My sever.js file included at the end. Thanks!

Full explanation:

I have an app with a separate backend folder and frontend folder. The backend is built with nodejs. The frontend is reactjs and is making axios calls successfully from localhost:3000 to the backend server running on localhost:5000. When I inspect element in chrome browser while running locally it shows the header for the Access-Control-Allow-Origin being successfully "set" by the backend.

In production on new render.com site i have the frontend on a static render.com app and the backend on render.com web service app. The both work / run fine as separate apps but when the frontend goes to make any api calls to the backend it gets the No Access-Control-Allow-Origin error. When i check the chrome inspect under network headers it doesn't show the Access-Control-Allow-Origin being set like it did in the local environment.

I have tried rebuilding front and back to clear cache but without success. I have set the Access-Control-Allow-Origin header to just "*" just to get it to show up on the live environment without success. I have tried several varieties of the following without success:

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();
});

Also:

app.use(
  cors({
    origin: "*",
    methods: ["GET", "POST", "DELETE", "UPDATE", "PUT"],
    credentials: true,
  })
);

None of these methods have worked. I made sure this is all before routes are being run as well in the server.js file as "high up" as i could put them in that file.

Screenshot of local headers on chrome inspect tool: enter image description here

production headers: enter image description here

Here is my server.js file that is attempting to set the headers and setup cors npm package. I left in several of the commented out tests just to show some of the things I have tested. The current test that is in there is my attempt to have the cors npm package set the headers:

const http = require('http');
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const bodyParser = require('body-parser');
const path = require('path');
const request = require('request')
const cookieParser = require("cookie-parser");
const session = require('express-session');
const MongoDBSession = require('connect-mongodb-session')(session);

require('dotenv').config();

const app = express();

// app.use(function(req, res, next) {
//   res.setHeader("Access-Control-Allow-Origin", "*");
//   next();
// });

// 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();
// });

// app.get('/*',function(req,res,next){
//   res.header('X-XSS-Protection' , 0 );
//   next(); // http://expressjs.com/guide.html#passing-route control
// });

// app.use(cors())

//actual connection to the mongodb server
const uri = process.env.ATLAS_URI;
mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true }
);
const connection = mongoose.connection;
connection.once('open', () => {
  console.log("MongoDB database connection established successfully");
})

const store = new MongoDBSession({
  uri: uri,
  collection: 'mySessions',
});

app.use(express.json());
app.use(express.urlencoded({
  extended: true
}));

let allowUrls = "*"

app.use(
  cors({
    origin: allowUrls,
    methods: ["GET", "POST", "DELETE", "UPDATE", "PUT"],
    credentials: true,
    // allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'device-remember-token', 'Access-Control-Allow-Origin', 'Origin', 'Accept']
  })
);


// app.use(cors())
// app.options('*', cors());
// 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();
// });

app.use(cookieParser());
app.use(bodyParser.urlencoded({extended: false})); //Post Body Parser

app.use(
  session({
    key: "userId",
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      expires: 365 * 24 * 60 * 60 * 1000,
    },
    store: store,
  })
);

// app.use(cors());
// app.use(cors({
//   origin: 'http://localhost:3000',
//   methods: ['POST', 'PUT', 'GET', 'OPTIONS', 'HEAD'],
//   credentials: true
// }));

const example = require('./routes/example');
//... lots more routes here

app.use('/example', example);
//... more here

app.get('/', (req, res) => {
  console.log('hit get request for /: ', res)
  res.sendStatus(200)
})

const port = !process.env.NODE_ENV ? 5000 : process.env.PORT;

app.listen(port, () => {
  console.log(`Server is running on port: ${port} process.env.NODE_ENV = ${process.env.NODE_ENV}`);
});

Solution

  • I figured it out. I ditched cors npm and just use res.header method since my main issues was that I could figure out how to get cors to set the origin header:

    app.use(function(req, res, next) {
          // res.header("Access-Control-Allow-Origin", "*");
          const allowedOrigins = ['http://localhost:3000', 'http://gamebrag.onrender.com', 'https://gamebrag.onrender.com'];
          const origin = req.headers.origin;
          if (allowedOrigins.includes(origin)) {
               res.setHeader('Access-Control-Allow-Origin', origin);
          }
          res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
          res.header("Access-Control-Allow-credentials", true);
          res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, UPDATE");
          next();
        });
    

    Made sure it was as high up as possible but after const app = express();

    I am guessing I was accidentally including app.use(cors()) with the res.headers which also messed things up. Render.com was also having issues with their free web services in the oregon/west usa area which I resolved by creating a new free web service in usa east.