0

I'm using Express as a simple backend for my client application. When trying to make a request to the endpoint GET /urls below it keep getting this message:

Access to fetch at 'http://localhost:5000/urls' from origin 'http://localhost:3000' has been 
blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested 
resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to 
fetch the resource with CORS disabled.

My Express server looks like so:

require("dotenv/config");
const express = require("express");
var bodyParser = require("body-parser");
const app = express();
const cors = require("cors");
const mongoose = require("mongoose");
const ShortUrl = require("./modules/shortUrl");

var whitelist = ['http://localhost:3000']
var corsOptions = {
  origin: function (origin, callback) {
    if (whitelist.indexOf(origin) !== -1) {
      callback(null, true)
    } else {
      callback(new Error('Not allowed by CORS'))
    }
  }
}
app.use(cors());
app.use(express.urlencoded({ extended: false }));
app.use(bodyParser.json());

mongoose
  .connect(process.env.MONGO_DB_CONNECTIONSTRING, {
    useNewUrlParser: true,
    useUnifiedTopology: true
  })
  .then(() => console.log("\nConnected to Mongo Database\n"));

app.get("/urls", cors(corsOptions), async (req, res) => {
  const shortUrls = await ShortUrl.find();
  res.send({ serverBaseUrl: process.env.SERVER_BASE_URL, shortUrls });
});

app.post("/url", cors(corsOptions), async (req, res) => {
  console.log(req.body);
  await ShortUrl.create({ full: req.body.fullUrl });
  res.send();
});

app.get("/:shortUrl", cors(corsOptions), async (req, res) => {
  const url = await ShortUrl.findOne({ short: req.params.shortUrl });

  if (url === null) return res.sendStatus(404);

  url.clicks++;
  await url.save();

  res.redirect(url.full);
});

app.listen(process.env.PORT || 5000);

In my web application I'm using a fetcher, I quickly typed up so it could be something in there which isn't quite right:

const createFetchOptions = (method, body = undefined) => {
  const options = {
    method,
    headers: {}
  };

  if (body && body instanceof FormData) {
    options.body = body;
  } else if (body) {
    options.headers["Content-type"] = "application/json";
    options.body = JSON.stringify(body);
  }

  return options;
};

const Fetcher = {
  get: async url => {
    const res = await fetch(url, createFetchOptions("GET"));
    return res;
  },

  post: async (url, body) => {
    const res = await fetch(url, createFetchOptions("POST", body));
    return res;
  }
};

export default Fetcher;

This is a copy of my package.json in case it's to do with a version issue:

{
  "name": "url_shortner",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon server.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "body-parser": "^1.19.0",
    "cors": "^2.8.5",
    "dotenv": "^8.2.0",
    "ejs": "^3.0.1",
    "express": "^4.17.1",
    "mongoose": "^5.9.4",
    "shortid": "^2.2.15"
  },
  "devDependencies": {
    "nodemon": "^2.0.2"
  }
}
halfer
  • 19,824
  • 17
  • 99
  • 186
Chris Marshall
  • 740
  • 1
  • 9
  • 25
  • Are you using React? if so try [this](https://stackoverflow.com/questions/58372337/how-to-fix-cors-error-request-doesnt-pass-access-control-check) – awran5 Mar 12 '20 at 21:44

1 Answers1

0

When you use app.use(cors()); it becomes middleware for all requests. Therefore, you don't need to manually add it to your routes. If you want to whitelist one particular domain for all routes, then you can utilize the origin option (I set it as a process string variable to be more flexible for development and production environments):

const { CLIENT } = process.env;

app.use(
  cors({
    origin: CLIENT, // "http://localhost:3000" for dev and "https://example.com" for production
  })
);
Matt Carlotta
  • 18,972
  • 4
  • 39
  • 51