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:
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}`);
});
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.