Using node.js and express to process a POST request - javascript

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'

Related

Node.js client can't see data from Express server

I am setting up a Client/Server communication between my tablet and my PC. My Client cant get any data from the server, what am I doing wrong.
My PC is running a Node.js server (using Express) and my tablet runs a client written in Node.js (using Express). I can access the server via the browser and get the data, but not through the javascript code.
My SERVER code is:
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('App requested a connection');
});
app.listen(3000, () => console.log('Listening on port 3000!'));
app.get("/boxes", function (req, res)
{
//res.send(req.params[0]);
res.send("All boxes are in the basement");
});
My CLIENT code is:
const express = require('express');
const app = express();
console.log("Client working ...");
app.get("http://127.0.0.1:3000/boxes", function (req, res)
{
console.log("inside...");
console.log(res);
});
The CLIENT should return "All boxes are in the basement" and I get this when I use a browser but it doesn't work if I run the client code. The only message I get from client is "Client working ...".
Does anybody know what I am doing wrong?
Cheers
Express is a library for setting up and configuring an http server for incoming requests. It does not make outgoing requests to other servers. So, your client code is not a client at all.
Several problems here:
127.0.0.1 refers to your local device so your client is referring to itself when it uses 127.0.0.1.
In your client app.get("http://127.0.0.1:3000/boxes") is not a request for data. That attempts to set up an Express route for incoming requests as if you were declaring a second server. But, it's not even done correctly because you would only use the path there.
For a client to make a request of some other server, you would need to use a library call that actually does http requests. For example, you could do something like this:
Code:
const rp = require('request-promise');
rp.get("http://ipaddressOfServer:3000/boxes").then(data => {
// have response here
}).catch(err => {
// error here
});
I chose to use the request-promise library, but there are multiple different ways to make an http request. You can also use http.get() (lower level), request() (from the request library) or axios() from the axios library, etc...
Note, the computer your server is on (assuming it's running a desktop OS) will also have to probably turn of it's local firewall (e.g. windows firewall) or set up a specific rule to allow incoming connections on port 3000. Without that, the incoming connection will be blocked (for security reasons).

404 when making a request to express route

I am trying to understand express and how it handles routes.
I have a domain set up with the following structure
/
app.js
/public_html
index.html
In app.js, I set up my express server:
let app = express();
app.post('/list', (request, response) => {
//get data then...
response.send(data)
});
app.use(express.static('public_html'))
app.listen(3000, function(){
console.log('listening');
});
I run the app with node app.js
Then, in index.html in the public_html directory, I am trying to request the data. I just did a simple:
fetch('/list').then(function(response) {
console.log(response)
})
But I get a 404 as the response.
I'm a bit confused about a couple of things:
My web server (Apache / Ubuntu) is set up to serve html out of the public_html directory by default. Does that mean my whole node app structure needs to be moved into the public_html folder and the actual html moved into a static folder or something?
What about the port? The node app listens on port 3000 - but I'm not sure how (or if) to make a request to that port specifically.
Route path - I am posting to /list but should it be ../list?
I haven't yet found a configuration for this app that works yet. Any help would be appreciated.
Use following code. Use ajax instead of fetch and method must be POST. Fetch is not working as it is get request by default.
Option 1
$.ajax({
method: "POST",
url: "/list"
})
.done(function( msg ) {
alert( "Data " + msg );
});
Option 2
Change only following code => POST to GET
app.get('/list', (request, response) => {
//get data then...
response.send(data)
});
Option 3
Use POST in fetch
fetch("/list",
{
method: "POST"
})
.then(function(data){ alert( "Data " + data ); })
Thanks to #vesse for suggesting option 3
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
My web server (Apache / Ubuntu) is set up to serve html out of the public_html directory by default. Does that mean my whole node app structure needs to be moved into the public_html folder and the actual html moved into a static folder or something?
Node.js and Apache can use the same static folder without conflict, but they both cannot listen on the same port. It is likely your Apache server is already running on port 80. If your Node.js server runs on port 3000, requests to port 80 will not match routes you write in your app and thus 404 will return (unless of course you had the same routes in a separate Apache hosted application).
What about the port? The node app listens on port 3000 - but I'm not sure how (or if) to make a request to that port specifically.
Since Apache is probably already listening on port 80, any request you send to http://localhost will hit your Apache server. Instead, you must make requests that include a port number, http://localhost:3000 will hit your Node.js server.
Route path - I am posting to /list but should it be ../list?
No, you should post to /list and also regard all the points Rakesh made in his answer so that you correctly match POST to POST from client to server or switch to GET if that's more appropriate. As in the second point, be sure you are posting to http://localhost:3000 and not just http://localhost. As you pointed out, one is Apache and the other is Node.js
Finally, here's the static server line of code I use when serving from a folder that is adjacent to my app script:
app.use('/', express.static(__dirname + '/public_html'));
With this, all files you put in the public_html folder become navigable in your application, which includes everything Apache related as well. Note __dirname is the always the directory from which the currently executing script is run. To visit this site, simply go to http://localhost:3000 in your browser and you should see your index file.

Why do I get a Bad request when I run server.js and client.js and access localhost?

I am new to node.js
I am trying to use the pub/sub faye nodemodule to create a publish/subscribe web application.
I have the following files and folders: My dependencies in the node_modules folder, a sever.js file, and a client.js
My server.js contains the following code:
var http = require('http'),
faye = require('faye');
var server = http.createServer(),
bayeux = new faye.NodeAdapter({mount: '/'});
bayeux.attach(server);
server.listen(8000);
As for my client.js file, it contains the following code:
var faye = require('faye')
var client = new faye.Client('http://localhost:8000/');
client.subscribe('/messages', function(message) {
alert('Got a message: ' + message.text);
});
client.publish('/messages', {
text: 'HAI!'
})
I go to my terminal and run node server.js and node client.js
When I go to my browser and run localhost:8000, all I get is a Bad request.
Why am I getting this? I am suspecting I don't have any page to display something.
Could someone please point out to me what I am missing.
Thanks.
You're getting that error because you've mounted Faye at /. So if you try browsing to /, the server is expecting a Faye client, not a normal HTTP request.
There is a browser client example that shows how to connect with Faye mounted at /faye. You can also pass in a request handler into http.createServer() that allows you to handle the request before Faye does, in case you want to respond to the particular request.

How Can I Use Node.js With Cappuccino?

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

Can I configure expressjs to serve some pages over http and others over https?

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.

Categories