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.
You should use node to serve up the Cappuccino application so it's all on the same port.
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
Related
I am developing website using AngularJS and host it within NodeJS (Express JS) web service. The AngularJS uses the data on some endpoints served by NodeJS. In another word, the NodeJS has endpoints which serve AngularJS web page and providing data needed.
Before host the webpage on my virtual machine (web service), I use my host machine to host it. The webpage then tried to request the data to my virtual machine's endpoint and it works fine.
However, when I'm hosting it on my virtual machine (web service) and changed to request data on my localhost (http://127.0.0.1:3000/data), I am now getting GET http://127.0.0.1:3000/data net::ERR_CONNECTION_REFUSED error.
What I have tried
First, I thought it was occurred because of cross origin resource sharing, so I am enabling that in my NodeJS by adding these lines of code (taken from this site):
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();
});
However, it still does not help at all. I am still getting the same error message.
Later, I thought it probably my firewall was blocking the access. I then turned off my firewall and it still failed to fix my problem.
I believe it happened because of my webpage trying to access endpoint on its localhost API, which should be overcome with CORS handling on my first attempt.
What is causing this exactly if it is not CORS? How do I overcome this issue? Any help would be appreciated.
Update: Node JS Route Code
var express = require('express');
var app =express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/admin/login/:user/:pass', function(appReq,appRes){
appRes.status(200).send('1');
appRes.end();
});
app.get('/*', function(appReq, appRes){
fs.readFile('./public/index.html', function(err,data){
if (err) {
appRes.writeHead(500);
appRes.end('Error loading html');
}
else {
appRes.writeHead(200);
appRes.end(data);
}
});
});
app.listen(port, function(){
console.log('express app listening at http://'+hostname+":"+port+'/');
});
Here is my AngularJS GitHub repo
Turns out using localhost IP is wrong. It is probably due to the JavaScript is sent to the client and the browser then interprets localhost is the client's localhost. Therefore, changing the localhost to my actual IP address solved my problem.
I'm trying to use sockets to connect to a Node server I'm running localy
but I keep on getting 'info - unhandled socket.io url' on the server side
+
"XMLHttpRequest cannot load http://localhost:8080/socket.io/?EIO=3&transport=polling&t=1424356590540-0. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access." on chrome (using address localhost:8000/index.html)
// top six lines of code to see setup
var express = require('express'),
app = express(),
http = require('http'),
server = http.createServer(app),
io = require('socket.io').listen(server);
server.listen(8080);
also I'm using python SimpleHTTPServer on port 8000
client code is:
var socket = io.connect('http://localhost:8080');
socket.on('connection', function(){
console.log("connected")
});
using https://cdn.socket.io/socket.io-1.3.4.js" version of sockets.io
I'm assuming the html is irrelevant since I don't have any javascript code in it (except references to angular and jquery)
That's a problem with CORS.
Since your web page is on localhost:8000 and the Socket.io server is on localhost:8080 (two different ports, so two different servers), to allow async requests between the two of them you need to enable CORS. Browsers require that for security reasons.
Your server seems to be using Express. Enabling CORS in Express is quite easy, thanks to NPM packages like cors. Alternatively, look at some questions on SO, like: How to allow CORS?
I have a static site, a simple single page layout that I deploy in Dokku. I need to make a redirect (301) from www to non www and from *.website1.com to website2.com, but I don't know how. I was trying to use express-force-domain in npm but it makes my URL's crazy and having some redirect loops, I was trying other methods that I find on the web but none succeeds.
my server.js is:
var express = require('express')
var app = express();
app.set('port', (process.env.PORT || 80))
app.use(express.static(__dirname + '/public'))
app.get('/', function(request, response) {
response.send('Hello World!')
})
app.listen(app.get('port'), function() {
console.log("Node app is running at localhost:" + app.get('port'))
})
That is the version that works, but without redirects.
res.redirect(301, 'http://yourotherdomain.com' + req.path)
See Express documentation.
To anyone arriving here from Google, while #frederic's answer is still what is recommended by the express docs, the response.send(status, body) style has been deprecated and will generate a warning (I am on express 4.13.4 at time of writing), and more importantly I found that it no longer produced the desired result when redirecting.
As #Markasoftware mentioned, to achieve an automatically followed 301, you need to set the location header to the url you want. The request body can be empty:
response.set('location', 'https://my.redirect.location');
response.status(301).send()
As far as I understand it, to set an HTTP 301 code, you would set the response code to be 301 and then set the Location header to whatever url you want it to redirect to. I don't think this is the preferred way to do www to non-www urls though
I am new to learning AJAX and new to web development at all, and I am having trouble having my local server and my remote server process a post request. I am using node.js and the express module.
Here is the code of my server:
var express = require('express');
//start server
var app = express.createServer();
//handle requests
app.post('/hello', function(req, res){
res.send("hello");
});
app.listen(8888);
Pretty basic, I know. To test this, I create an XMLHttpRequest manually through the console in Chrome (I have disabled the Cross-Origin policy to test on my local machine):
var xhr = new XMLHttpRequest();
xhr.open('POST', 'localhost:8888/hello', true);
xhr.send('name=me'); //body of request is irrelevant at this point
When I send the request to my local machine, it returns immediately and says it failed. When I send the request to my remote server (where localhost is replaced by my server's IP) I don't get the error in my console, but when I check the xhr object's status is failed.
I don't know whether the problem is with the way my server is written, or the way I am sending the request to the server. However, I have been looking at tutorials and examples that show express processing post requests like I do above, and other tutorials that show sending POST requests like I do above.
Sending and processing GET requests seems to work fine. I must be missing something.
Thanks, Xaan.
You need to include HTTP in your URL when you issue the POST:
xhr.open('POST', 'http://localhost:8888/hello', true);
XHR does not work if the calling js is not served by a webserver.
What you should do is add a simple route on your Express server
app.get('/', function( req, res) {
res.sendfile('index.html');
})
Where index.html contains your testing code.
If you want to test from a different webserver and be confronted with the annoying Cross-Origin policy you can also use this super usefull command to spawn a webserver in your current folder:
python -m SimpleHTTPServer
I use it so often that I actually alias it:
alias www='python -m SimpleHTTPServer'
Based on the response to this question:
How do I configure nodejs/expressjs to serve pages over https?
I've been trying to set up the equivalent of:
var express = require('express');
var fs = require("fs");
var crypto = require('crypto');
var app = express.createServer();
var appSecure = express.createServer();
var privateKey = fs.readFileSync('privatekey.pem').toString();
var certificate = fs.readFileSync('certificate.pem').toString();
var credentials = crypto.createCredentials({key: privateKey, cert: certificate});
appSecure.setSecure(credentials);
app.get('/secretStuff', function(req,res) {
//redirect to https
}
appSecure.get('/secretStuff', function(req, res) {
//show you the secret stuff
}
Is this something that's doable with the current release of expressjs and node 2.4?
Yes, this can be done and it looks like you already have most of what you need. Just send the redirect in your app.get handler
app.get('/secretStuff', function(req,res) {
res.redirect('https://' + req.header('Host') + req.url);
}
Also make sure you do something like app.listen(80) and appSecure.listen(443) to actually start the servers on the appropriate port. Otherwise be sure to construct the HTTPS URL with the correct port. For production, this thing is typically handled outside of your app server (node.js) with a reverse proxy like nginx. It is trivial to do this in nginx which will let your node.js process run as non-root and remove the need to have clients directly connecting to node.js, which is not as battle-hardened as nginx for serving live internect TCP connections (I'm paraphrasing Ryan Dahl himself here).
You can only serve a web page over the connection that the request came in. If the request did not come in over https, you can't send the response that way.
So, first you have to be listening for both http and https requests. If a request comes in over http that you want to answer over a secure connection, do not do any processing but immediately redirect it to an https url. Then when the client reissues the request, process as normally.
If the framework uses JSGI then you can probably use the redirect module from Jack otherwise you will have to do it yourself. The details are at the link, i.e. response code 301 and Location: header with the https URL.