How to fix CORS ('Access-Control-Allow-Origin') error in Meteor app?


#1

Hi Meteor experts!! noob here, so please excuse the amateur questions.

When trying to access an external API using Meteor’s HTTP package via HTTP.get in this way:

Meteor.http.get(remoteServerAPIURL,function(error, result) {
                          ....
                });

I receive the following error from the remote server:

XMLHttpRequest cannot load https://remote.server.com/search?term=JOHN%20DOE. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 501.

On my local machine, I get this error, but the response still happens to come through, but after deploying my meteor app to my DigitalOcean droplet, using “MUP deploy”, I get the same error, but the response never comes through, and my app fails to get the data it needs from the remote API.

How can this be fixed?

Thanks a ton in advance! I would greatly appreciate your help with this!!


#2

This isn’t really a Meteor issue; rather, it’s the same-origin policy at work.

The best way to solve this is to move your remote API consumption code to the server, and create a Meteor method to call it from the client.

If that’s not possible, have a look at the various ways to circumvent the same origin policy. I’ve done this recently with my JavaScript community size comparison table - client-only code that bypasses the policy for Twitter and Google. Hacks can get spectacularly ugly - proxy via http://anyorigin.com/, or even use YQL.

But again, resort to this only if for some really good reason you can’t move your API access code to the server.


#3

You could also ask the maintainer of the API, I’ve done it several times, some people just don’t know.

http://enable-cors.org/


#4

Thanks a ton @dandv and @benjick! will look into the links and resources you’ve shared, and get it fixed.

I’m curious though, is there a reason why I encounter this error with Meteor (server side call using the HTTP GET method) and not with a standard NodeJS app (server side call with the REQUEST npm module)?

Thanks again!


#5

CORS shouldn’t kick in if you make the request from the server.


#6

Are you sure you are doing it server side?


#7

thank you for pointing that out @dandv and @benjick! My mistake entirely; I made the assumption that code within one of my collections files, was executed ONLY on the server by default; I now went ahead and wrapped the entire collection related methods (which included calls to external APIs), within a if(Meteor.isServer) block and it works perfectly fine now, with no CORS related errors as seen previously.

Thanks a ton! I hope I’ve fixed it in a non-hackish way.

My collections files, currently are placed within the "projectRoot/lib/collections" folder; is this as per best-practices? or should my collections files be moved to the “projectRoot/server” folder instead, and then the collection methods, I assume can also be removed from within the if(Meteor.isServer) block (since the file itself resides within the “server” folder)?


#8

Collections should be declared on both the client and the server.

/lib/collections looks fine to me. You can then put your methods in /server/methods/http.js or something like that


#9

Collections are normally declared on both client and server (lib is a good place), but it’s quite possible to have client-only and server-only collections.


#10

Thank you for the clarification @benjick @robfallows!!!


#11

Hey everyone, i put the folowing code on my “main.js” server-side.

And it’s still returning the problem about CORS.

Can somebody help me?


#12

Hi @olivermathe,

have you solved your issues by following the above way.
Can you please provide a solution, if you solved it in another way.

Thankyou


#13

Came to this thread last night via google looking for a solution. Ended up patching this together which works for me. Include somewhere in server-only code:

// Proxy for Northwind OData service calls - can't call directly on the client
// due to CORS error (browser security)
// Uses package cfs:http-methods
// https://atmospherejs.com/cfs/http-methods

HTTP.methods({
  '/oDataProxy': callODataService,
  '/oDataProxy/:p1': callODataService,
  '/oDataProxy/:p1/:p2': callODataService
});

function callODataService() {

  let url = 'http://services.odata.org/V2/Northwind/Northwind.svc';

  // Build rest of url from parameters - painful we have to do it this way but there's
  // no way with http-methods to gulp the rest of a url after oDataProxy into one parameter
  if (this.params.p1) {
    url = url + "/" + this.params.p1;
    if (this.params.p2) {
      url = url + this.params.p2;

      // TODO: Add more parameters here as required
    }
  }
  console.log("Handling oDataProxy request for " + url);
  const response = HTTP.get(url);

  // Get service call response headers and add them to our response
  for (const property in response.headers) {
    if (response.headers.hasOwnProperty(property)) {
      this.addHeader(property, response.headers[property]);
    }
  }

  // Return service call content
  return response.content;
}

#14

I too had this problem with Meteor 1.4x. I have my component calling Meteor.methods in /rootDir/imports/api/things/methods.js

I’m pretty sure this is running on the server as I put in a console.log('running method on server'); line and it shows in my console (still developing on localhost) but still getting the CORS error. I then wrapped the console.log within a if(Meteor.isServer) block and the note shows only in my terminal and not in the browser console. But still got the CORS error (and like above, the error is thrown, but then the remote object is returned – but wanted to solve as noted above when not on localhost this might still be a problem).

So then I wrapped the HTTP.call block within the if(Meteor.isServer) and the error went away and the remote object was returned.

Not exactly sure why. I even tried to move that method to /rootDir/imports/api/thing/server/methods.js and that didn’t work, but alas, the isServer saved the day.


#15

I use this approach to take care of CORS:

import  cors  from 'cors';

[.....]

//http://stackoverflow.com/a/33483759/364966
var whitelist = [
    'http://localhost:3000',
];
var corsOptions = {
    origin: function(origin, callback){
        var originIsWhitelisted = whitelist.indexOf(origin) !== -1;
        callback(null, originIsWhitelisted);
    },
    credentials: true
};
myServer.use(cors(corsOptions));

#16

How are you using that with Meteor?


#17

I’m using it in server/main.js.


#18

How exactly are you doing that?


#19

@nadeemjq Just importing the cors module and calling it. Can you provide more information with regard to what your question is?


#20

But how are you actually attaching it to anything meteor related, like “myServer.use(cors(corsOptions));” ?