1

I'm currently running two sites, one PHP based, one node.js based. The node.js version is the api so let's call it "api.com"

the php site ( php.com ) is the HTML/JS angular based visual site "php.com" that calls through to "api.com" using angular resource POSTs.

So all was good until recently I start gettting this error.

MLHttpRequest cannot load https://api.com/create. 
Response to preflight request doesn't pass access control check: 
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://php.com' is therefore not allowed access. 
The response had HTTP status code 400.

So a few things to note. the api.com is from an https site where as php is http.

In the node.js restify api.com site, it is doing what I think is necessary for CORS support.

    // Allow CORS since other sites may be calling this
    server.use(
      function crossOrigin(req,res,next){
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept" ); // was "X-Requested-With"
        return next();
      }
    );

However it seems to still give the same CORS error. I'm new to this CORS stuff so not sure if it's the PHP server or Node server that needs to issue the header to allow this call to happen?

For sanity I tried adding to the php.com .htaccess file the following...

Header set Access-Control-Allow-Origin "*"

But again still no luck. Really confused as to what is happening and how to do this correctly. I'm pretty sure this is a simple error I'm making so any advice is greatly appreciated in explaining how

**browser (chrome) -> web server (php.com) -> api server (node.js) **

and which server(s) should be sending out the CORS headers

sradforth
  • 2,078
  • 1
  • 22
  • 35
  • Possible duplicate of [How to disable OPTIONS request?](http://stackoverflow.com/questions/29954037/how-to-disable-options-request) – Quentin May 08 '17 at 10:55

2 Answers2

2

Restify has a CORS plugin built in. From the docs:

server.use(restify.CORS({
    origins: ['https://foo.com', 'http://bar.com', 'http://baz.com:8081'],   // defaults to ['*']
    credentials: true,                 // defaults to false
    headers: ['x-foo']                 // sets expose-headers
}));
JWL_
  • 829
  • 7
  • 14
1

Use server.opts method to wirte your own handler for OPTIONS request. Below is the example you can use.

Also tell me if you are using set-credentials flag to true while making request from the browser. This handle in that case would have to respond with access cookies.

In the example below, I am returning the allowed origin for exact match. You can tweak it to be substring match also. But always return the exact value as found in request header origin in the response header 'Access-Control-Allow-Origin'. Its a good practice.

server.opts('/api/(.)*', (req, res) => {
const origin = req.header('origin');
const allowedOrigins = ['example.com', 'example.org'];
if (allowedOrigins.indexOf(origin) === -1) {
    //origin is not allowed
    return res.send(405);
}
//set access control headers to allow the preflight/options request
res.setHeader('Access-Control-Allow-Origin', header);
res.setHeader('Access-Control-Allow-Headers', 'Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version');
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PUT,PATCH,DELETE,OPTIONS');

// Access-Control-Max-Age header catches the preflight request in the browser for the desired
// time. 864000 is ten days in number of seconds. Also during development you may want to keep


   // this number too low e.g. 1.
    res.setHeader('Access-Control-Max-Age', 864000);
    return res.send(200);
  });
varun249
  • 1,366
  • 2
  • 9
  • 9