3

I'd like to have a client application implemented in Cappuccino that uses Node.js as the server.

I have currently got Node running with Express:

var express = require( 'express' );

var app = express();

app.get( '/an_endpoint', function(req, res){

    res.send('Hello From Node Express!\n');

});

app.listen(1337);

Which is verifiable with:

$ node hello_echo.js
$ curl http://127.0.0.1:1337/an_endpoint
> Hello From Node Express!

As far as the client code, it's a simple little app, with a button that does this when clicked:

// in did finish launching
[button setTitle:"Ping Node"];
[button setTarget:self];
[button setAction:@selector(doPing:)];

- (void)doPing:(id)sender
{
    var connection = [CPURLConnection connectionWithRequest:[CPURLRequest requestWithURL:'http://127.0.0.1:1337/an_endpoint/'] delegate:self];
}

- (void)connection:(CPURLConnection) connection didReceiveData:(CPString)data
{
    alert('Node Says: ' + data);
}

- (void)connection:(CPURLConnection)connection didFailWithError:(CPString)error
{
    alert('Error: ' + error);
}

When I load the app ( from http://127.0.0.1:8080/NewApplication/index.html ) and click the button, in Google Chrome, on OS X, I get the following errors in the console, the first due to the latter:

OPTIONS http://127.0.0.1:1337/an_endpoint/ 404 (Not Found) Objective-J.js:716
        XMLHttpRequest cannot load http://127.0.0.1:1337/an_endpoint/. 
Origin http://127.0.0.1:8080 is not allowed by Access-Control-Allow-Origin.

Which, is obviously due to the fact that my node server is at :1337, and my Cappuccino app is at :8080, which are technically different domains, due to the port part.

A bit of research led me to this post, which recommends considering the use of JSONP to inject remote scripts into the app. It sounds very messy, so I'd like to not go that route if not necessary.

So, my question is, how can I allow Cappuccino and Node.js to work together in harmony? It seems that if I can tell the Cappuccino app to use this ( header("Access-Control-Allow-Origin", "*"); ) header, all should be well, but I'm not sure how to do that. I tried having Node send that header, and it didn't seem to do anything.

Josh
  • 12,448
  • 10
  • 74
  • 118

2 Answers2

0

You should use node to serve up the Cappuccino application so it's all on the same port.

Me1000
  • 1,760
  • 1
  • 12
  • 14
  • How would I do that? Right now it is using some Jack and Jill thing. – Josh Sep 02 '12 at 04:01
  • Jack is a development server, similar to Rack. It's only used to get by the terrible same origin policy for local development in Chrome. You serve up the Cappuccino app the same way to serve up any static file using node/express. – Me1000 Sep 02 '12 at 19:14
0

The problem here is lack of configuration for CORS protection (Cross Origin Resource Sharing).

Somewhat simplified: The backend checks to see if the frontend is allowed to connect to the resource by checking to see if the request comes from the same server (protocol, domain, host, and port). in your case, the port is different and therefor the backend says NO and the frontend doesn't even actually perform the request. (This all happens in a preflight check).

In order to really solve this issue, you should learn about CORS but you really only need to do that if you plan to deploy something out of development. until then, you can just 'enable CORS' on your backend so it'll allow the frontend access:


var express = require( 'express' );
var cors = require( 'cors' );

var app = express();
app.use(cors);

app.get( '/an_endpoint', function(req, res){

    res.send('Hello From Node Express!\n');

});

app.listen(1337);

This will allow all referers through to your code. Here are some more granular examples

Kris
  • 40,604
  • 9
  • 72
  • 101