Filip Markoski
Filip Markoski

Reputation: 333

ExpressJS: Response to preflight request doesn't pass access control check

I'm running an Angular 4 (angular.io/angular cli) app on http://localhost:4200 as well as an ExpressJS app on http://localhost:3000

ExpressJS app github link

Angular app github link

What I've tried

I've spent hours on this issue, I've found a solution which is to use a chrome extension to disable CORS. I've tried to add the middleware headers for CORS on my own in the ExpressJS app, because as I've read this is only a server-side issue and not a client-side one, therefore it's not angular's problem. I've tried to add the cors npm module. That didn't work too. I've deliberately added the cors lines before my routes & my static folder definition in app.js. I have no idea what the issue is..

The error

Failed to load http://localhost:3000/users/post: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:4200' is therefore not allowed access.

The console.log from the ExpressJS app

OPTIONS /users/post 200 1.206 ms - 13

How is it 200? Why does it think that it's okay?

app.js

    var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();

// Add headers
/*
app.use(function (req, res, next) {

    // Website you wish to allow to connect
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:4200');

    // Request methods you wish to allow
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

    // Request headers you wish to allow
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

    // Set to true if you need the website to include cookies in the requests sent
    // to the API (e.g. in case you use sessions)
    res.setHeader('Access-Control-Allow-Credentials', true);

    // Pass to next layer of middleware
    next();
});
*/

/*var corsOptions = {
    origin: ['http://localhost:4200'],
    optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
};
const corsOptions = {
    origin: '*',
    method: ['GET', 'POST'],
    //allowedHeaders: ['Content-Type', 'Authorization', 'Origin', 'Accept', 'X-Requested-With'],
    optionsSuccessStatus: 200 //Some legacy browsers (IE11, various SmartTVs) choke on 204
};
app.use(cors(corsOptions));
app.options('*', cors());
*/

const corsOptions = {
    origin: 'http://localhost:4200',
    method: ['GET', 'POST'],
    //allowedHeaders: ['Content-Type', 'Authorization', 'Origin', 'Accept', 'X-Requested-With'],
    optionsSuccessStatus: 200 //Some legacy browsers (IE11, various SmartTVs) choke on 204,
    credentials: true
};
app.use(cors(corsOptions));

var index = require('./routes/index');
var users = require('./routes/users');

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
app.use('/users', users);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handler
app.use(function (err, req, res, next) {
    // set locals, only providing error in development
    res.locals.message = err.message;
    res.locals.error = req.app.get('env') === 'development' ? err : {};

    // render the error page
    res.status(err.status || 500);
    res.render('error');
});

module.exports = app;

users.js

    var express = require('express');
var router = express.Router();

var conn = require('../connect')();
//var cors = require('cors');
var table = "users";

router.get('/', (req, res, next) => {
    var query = `SELECT * FROM ${table}`;
    console.log(query);

    conn.query(query, (err, result, fields) => {
        if (err) throw err;
        res.send(result);
    });
});

router.post('/post', (req, res) => {

    //console.log("Body: ", req.body);
    /**
     * Test Case:
     * {"user":{"name": "jack","email": "[email protected]","password": "jackPass"}}
     * */

    var name = req.body.name;
    var email = req.body.email;
    var password = req.body.password;

    var query = `INSERT INTO ${table} VALUES (null, "${name}", "${email}", "${password}")`;
    console.log(query);

    conn.query(query, (err, result, fields) => {
        if (err) throw err;
        res.send(result);
    });
});

router.get('/:search/', (req, res, next) => {

    var search = req.params.search;
    var query = "";

    if (isNaN(search)) {
        query = `SELECT * FROM ${table} WHERE name LIKE '%${search}%'`;
    } else {
        query = `SELECT * FROM ${table} WHERE id='${search}'`;
    }
    console.log(query);

    conn.query(query, (err, result, fields) => {
        if (err) throw err;
        res.send(result);
    });
});

module.exports = router;
var express = require('express');
var router = express.Router();

var conn = require('../connect')();
//var cors = require('cors');
var table = "users";

router.get('/', (req, res, next) => {
    var query = `SELECT * FROM ${table}`;
    console.log(query);

    conn.query(query, (err, result, fields) => {
        if (err) throw err;
        res.send(result);
    });
});

router.post('/post', (req, res) => {

    //console.log("Body: ", req.body);
    /**
     * Test Case:
     * {"user":{"name": "jack","email": "[email protected]","password": "jackPass"}}
     * */

    var name = req.body.name;
    var email = req.body.email;
    var password = req.body.password;

    var query = `INSERT INTO ${table} VALUES (null, "${name}", "${email}", "${password}")`;
    console.log(query);

    conn.query(query, (err, result, fields) => {
        if (err) throw err;
        res.send(result);
    });
});

router.get('/:search/', (req, res, next) => {

    var search = req.params.search;
    var query = "";

    if (isNaN(search)) {
        query = `SELECT * FROM ${table} WHERE name LIKE '%${search}%'`;
    } else {
        query = `SELECT * FROM ${table} WHERE id='${search}'`;
    }
    console.log(query);

    conn.query(query, (err, result, fields) => {
        if (err) throw err;
        res.send(result);
    });
});

module.exports = router;

Upvotes: 1

Views: 6099

Answers (2)

Thijs Benjamin
Thijs Benjamin

Reputation: 1

I had the same issue, and turns out, the cors was not exactly the issue.
It had to do with how I used localhost and 127.0.0.1 interchangeably.

I was running my front-end on 127.0.0.1:3000, which caused some issues. As soon as I changed it to localhost:3000, everything worked as intended (including cors).

My cors settings:

app.use(
  cors({
    origin: 'localhost:3000',
  })
);

Hope this helps.

EDIT:
Also yes, it is fine if the return for cors is 200, or even 204. It will return 200 or 204 in case of success, in which case the endpoint exists, and the returned headers tell the requester what they are allowed to do on this endpoint.
In case the endpoint does not exist, a 404 will be returned.
see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS#preflighted_requests_in_cors

Upvotes: 0

Mike Tung
Mike Tung

Reputation: 4821

In your express app.js

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();
//rest of your app.get/post/whatevers

That should enable cors for you.

Upvotes: 3

Related Questions