yorchp
yorchp

Reputation: 93

Sails, React and Axios Error with CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource

I have really researched this problem and nothing is clear for SailsJS. I'm running the sails and react locally with npm start.

The verions:

The error: Access to XMLHttpRequest at 'http://localhost:1337/User/Read/2' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I really checked the tickets in stackoverflow.com and the docu in sails, also tested the different solutions and options, the only way I can work is with Moesif Origin & CORS Changer widget in chrome, but I need config the headers and the security for prod:

https://sailsjs.com/documentation/concepts/security/cors, https://sailsjs.com/documentation/reference/configuration/sails-config-security

Request Headers:

GET /User/Read/2 HTTP/1.1
Host: localhost:1337
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 11_1_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Origin: http://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

My config in security.js for cors in sails is:

module.exports.security = {
  cors: {
    allRoutes: true,
    allowOrigins: ['http://localhost:3000'],
    allowCredentials: false,
    allowRequestHeaders: [
      'X-Powered-By', 
      'Content-Type', 
      'Accept', 
      'Origin',
      'Accept-Encoding',
      'Accept-Language',
      'Connection',
      'Host',
      'Origin',
      'Referer',
      'Sec-Fetch-Dest',
      'Sec-Fetch-Mode',
      'Sec-Fetch-Site',
      'User-Agent',
      'Pragma',
      'Cache-Control',
    ]
  },
  csrf: false
};

The Axios Request in React:

var axios = require('axios');
axios({
      method: 'get',
      headers: {     
        'Accept': 'application/json',
        'Content-Type': 'application/json;charset=UTF-8'},
      url: 'http://localhost:1337/User/Read/2',
    }).then(function (response) {
      console.log(response.data);
});

And the route request:

  'GET /User/Read/:id': {
    controller: "User", 
    action: "read"
  },

Upvotes: 0

Views: 4502

Answers (4)

Nishan B
Nishan B

Reputation: 855

Make sure to add authorization in allowed header to allow tokens / cookies to be passed to back-end

   
config/settings.js -> 

module.exports.security = {
  cors: {
    allRoutes: true,
    allowOrigins: '*',
    allowCredentials: true,
    allowAnyOriginWithCredentialsUnsafe: true,
    allowRequestHeaders : 'content-type,Authorization'
  }
}

Upvotes: 1

In /config/http.js file, uncomment the 'order' array fragment and add header params inside myRequestLogger method.

order: [
  'startRequestTimer',
  'cookieParser',
  'session',
  'myRequestLogger',
  'bodyParser',
  'handleBodyParserError',
  'compress',
  'methodOverride',
  'poweredBy',
  '$custom',
  'router',
  'www',
  'favicon',
  '404',
  '500'
],


 myRequestLogger: function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
  res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
  res.header('Allow', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
  res.header('X-Powered-By', '');
  return next();
},

Inside /config/cors.js (sails v0.12) or /config/security.js (sails v1.x) add the following code snippet

module.exports.security = { //sails v1.x, if is sails v0.12 change security for cors
  allRoutes: true,
  allowOrigins: '*',
  allowCredentials: false,
  allowRequestMethods: 'GET,POST,PUT,DELETE,OPTIONS,HEAD',
  allowRequestHeaders: 'content-type'
}

In case none of this works (which I find difficult to happen), add in the return of your controller method (but, I think it is not necessary):

  return res.set({
    'Content-Type': 'application/json',
    'Access-Control-Allow-Origin': '*',
  }).json({ status: true, //body });

Upvotes: 2

Sudhakar Behera
Sudhakar Behera

Reputation: 111

I just use like this

cors: {
    allRoutes: true,
    allowOrigins: "*",
    allowCredentials: false,
    allowRequestHeaders: "*",
  }

Make sure to add, client side host in allowOrigins: ['http://mywebsite.com] on production

Upvotes: 3

yorchp
yorchp

Reputation: 93

In the end, I solved it in this way:

On http.js in sails, added the req headers:

module.exports.http = {

  middleware: {
    order: [
      'cookieParser',
      'session',
      'bodyParser',
      'compress',
      'poweredBy',
      'appRequestLogger', // custom logger
      'router',
      'www',
      'favicon'
    ],

    appRequestLogger: function (req, res, next) {
      const env = process.env.NODE_ENV || 'development';
      sails.log.debug('<<------------------------------');
      sails.log.debug('Requested data :: ');
      sails.log.debug('  ', req.method, req.url);
      sails.log.debug('   Headers:');
      sails.log.debug(req.headers);
      if (env.toLowerCase() !== 'production') {
        sails.log.debug('   Params:');
        sails.log.debug(req.params);
        sails.log.debug('   Body:');
        sails.log.debug(req.body);
      }
      sails.log.debug('------------------------------>>');

      // This is a work around to allow CORS requests as Sails does not send these
      // headers in the response to preflight/actual requests even when they are
      // declared in config/security.js under CORS config

        res.header('Access-Control-Allow-Origin', '*');
        res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization');
        res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
        res.header('Allow', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
        res.header('X-Powered-By', '');

      // Check graphql preflight request, if yes then prevent the request reaching
      // the express-graphql server. Currently the express-graphql server only accepts
      // GET and POST hence rejects the preflight request. CORS needs that a server
      // accepts preflight requests to facilitate cross-site access. Therefore, return
      // immediately with a success.
      // Otherwise fall through by calling next()

      if (req.method === 'OPTIONS' && req.url.indexOf('graphql') > -1) {
        return res.status(200).send();
      } else {
        return next();
      }
    },

  },

};

Upvotes: 1

Related Questions