sock.js not allowing POST method for node server - javascript

Trying to bring up a node server that uses sock.js for websocket communication.
Can bring up the server fine and have established the websocket communication. However, we also need to POST to this instance with HTTP so that we can then send a message through the websocket. The message is dependent on the POST payload...
However, sock.js does not seem to be accepting the handler that we're creating, and is only allowing a GET method. This is causing a 405 HTTP code for any POSTs done to the server.
Please see following code. If I remove the sock.js implementation, I'm then able to process GET and POST requests with the server.
var app = require('http');
var sockjs = require('sockjs');
var sk = sockjs.createServer({ sockjs_url: '//cdn.jsdelivr.net/sockjs/1.0.1/sockjs.min.js' });
sk.on('connection', function (conn) {
console.log('connection' + conn);
conn.on('close', function () {
console.log('close ' + conn);
});
conn.on('data', function (message) {
console.log('message ' + conn,
message);
conn.write(message);
});
});
var server = app.createServer( function(req, res) {
if (req.method == 'POST') {
console.log("POST");
var body = '';
req.on('data', function (data) {
body += data;
console.log("Partial body: " + body);
});
req.on('end', function () {
console.log("Body: " + body);
});
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('post received');
}
else
{
console.log("GET");
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('get received');
}
});
sk.installHandlers(server);
I've tried different ways to set up the handlers, including following the example here; but regardless it just doesn't seem like I'm falling into my handlers but instead sock.js is not allowing POSTs.
If this is expected behavior from sock.js and is working the way it;s intended to, then recommendations for what to use would be appreciated. This is an attempt to move away from socket.io because that isn't working in all cases for us... but without being able to POST to the node server we probably won't be able to use sock.js either.

You're missing the prefix in your call to installHandlers. This results in sockjs handling all requests, rather than just those that are destined to it.
Just specify a prefix:
sk.installHandler(server,{prefix:"/whatever"});
It should of course match the prefix you use client-side.
Alternatively, if you don't want to use a prefix, use different ports.

Related

Stop execution after writing to text file with fs.writeFile

I have the following Node.JS (ran with Express) code :
let app = express();
app.use(cors());
app.get('/callback', function (req, res) {
// your application requests refresh and access tokens
// after checking the state parameter
var code = req.query.code || null;
var authOptions = {
url: 'https://accounts.spotify.com/api/token',
form: {
code: code,
redirect_uri: redirectUri,
grant_type: 'authorization_code'
},
headers: {
'Authorization': 'Basic ' + (new Buffer(clientId + ':' + clientSecret).toString('base64'))
},
json: true
};
request.post(authOptions, function (error, response, body) {
if (!error && response.statusCode === 200) {
var access_token = body.access_token,
refresh_token = body.refresh_token;
fs.writeFile('test.txt', 'HELLO', function (err) {
if (err) return console.log(err);
console.log('Hello World > helloworld.txt');
});
}
}
)
});
console.log('Listening on 8888');
app.listen(8888);
The route is used as a callback for a request to the Spotify Web API, thus I can get an access token.
Spotify then redirects to the callback function above, you can see it in the URI by looking at "redirect_uri".
If you need more information about the Spotify Authorization Flow, see here.
Here's the URI I'm using to authenticate my app to Spotify.
https://accounts.spotify.com/authorize?client_id=CLIENT_ID&response_type=code&redirect_uri=http://localhost:8888/callback&scope=user-read-private%20user-read-email%20playlist-modify-public&state=PexBrjEzISHepTp7&show_dialog=false
CLIENT_ID is replaced by my real CLIENT_ID in the request I make
My problem is located to the file writing part :
fs.writeFile('test.txt', 'HELLO', function (err) {
if (err) return console.log(err);
console.log('Hello World > helloworld.txt');
});
When the callback route is called by Spotify, I have the string "HELLO" wrote in my text file, so the file writing is functional.
But even if it has finished writing the string, the Chrome page is still running and "pending" on the server. It runs for a few minutes and then crash by saying that the page didn't sent any data. Why ?
I've looked at this page talking about the methods of writing to text files, using writeFile and writeFileAsync, but using both of them didn't solved my problem.
EDIT: I don't really want to stop the Express process! I just want to be able to process another request :)
Any idea ? Thanks in advance :)
You aren't returning anything from your route, try adding res.send({})
In your get route you are not sending response, you must send response irrespective of writing a file was successful or not.
Add below code post writing to file (as well as in if error case)
res.send({YOUR_CHOICE_RESPONSE_DATA})

ajax get to 3rd party server within express middleware results in 500 error

I have a requirement to access multiple devices over IP from an HTML5 web app.
My approach to working around the cross-domain impossibility of doing this all on the client side has been to "cook" requests from the client inside of express' middleware. A route receives a get or post from the client, and then performs a get or post to the 3rd party device identified by the payload from the client.
I'm using the code to get info from a device. It works just fine when I run it directly from file inside of a client I made for testing purposes. Running directly from file avoids the CORS difficulty because the client is also the server I guess.
When I run the same code from within an express route, I get a 500 error.
Am I trying to do something impossible? I'm only about a week into node, express etc so hopefully it's something dumb and easy to solve. I'm taking fact that I haven't been able to find any other questions quite like this as an indication that there's a proper way to achieve what I need.
// post to find a camera
router.post('/find', function(req, res) {
var url = 'http://' + req.body.addr + '/cgi-bin/aw_cam?cmd=QID&res=1';
console.log(url);
$.ajax({
type: 'GET',
url: url,
dataType: 'html',
success: function (result) {
console.log('success: ' + result);
res.send(result);
},
error: function (xhr, textStatus, err) {
console.log('error: ' + textStatus);
}
});
});
Here's what logged to the server console:
http://192.168.0.10/cgi-bin/aw_cam?cmd=QID&res=1
POST /cameras/find 500 126.593 ms - 1656
Thanks in advance!
ok I found how to do this. The trick is to use Node's built-in http messaging capabilities. I found a good article on how to do this here
The code below does exactly what I wanted from within my custom route middleware. I guess I just learned that I can only use AJAX how I wanted on the client side.
This lets me abstract the hairier details of the device control protocol into the server, leaving my client apps to use JSON/AJAX model to interact with them. Success!
var http = require('http');
// post to find a camera
router.post('/find', function(req, res) {
var url = 'http://' + req.body.addr + '/cgi-bin/aw_cam?cmd=QID&res=1';
console.log(url);
http.get(url, (response) => {
console.log(`Got response: ${response.statusCode}`);
var body = '';
response.on ('data', function(d) {
body += d;
});
response.on ('end', function () {
console.log('received: ' + body);
var reply = {};
if (body.indexOf('OID:') == 0) {
reply.msg = body.slice(4);
reply.ok = true;
} else {
reply.msg = body;
reply.ok = false;
}
res.send(reply);
});
// consume response body
response.resume();
}).on('error', (e) => {
console.log(`Got error: ${e.message}`);
});
});

Delete files from SERVER through web interface

I need to create a web interface where users can upload files, view info about those (already stored) files and delete them. I've already written the first two parts (I use Node.js server), but I'm having serious problems with deleting stored files.
My main problem is, that I don't know, how to make a request with info about the file user want to delete correctly. I supposed that I will simply use open() method like this
xhr.open('POST', '/delete', true);
and then just "catch" it with condition in server code like this:
if (req.url == '/delete' && req.method.toLowerCase() == 'post') {th
But this solutions keeps throwing error 404 - Resource not found.
So, could you please help me and describe some way which works for you?
Here is my server code.
And this file contains client-side JavaScript.
- there is the problem in function createStoredFilesTable() in $('.deleteLink').click() block.
The solution was pretty simple in the end - the problem was missing "return" in the end of DELETE block, so the program handled the request and continued to loading source codes, where it couldn't find anything, because request URL was '/delete'.
So, the correct block of the server code is here:
//-------------------------------------------------------------------------------------
//--- DELETE handling ---//
//-----------------------//
if (req.url == '/delete' && req.method.toLowerCase() == 'post') {
req.on('data', function (data) {
var filename = data.toString('ascii');
var jsonObj = require('./storedFilesList.json');
delete jsonObj[filename];
var jsonString = JSON.stringify(jsonObj);
fs.writeFile('storedFilesList.json', jsonString, function(err){
if (err) throw err;
fs.unlinkSync(__dirname + '/uploadedFiles/' + filename);
console.log('File ' + filename + ' was succesfully deleted.');
});
res.writeHead(200, {'content-type': 'text/plain'});
res.write('OK');
res.end();
});
return;
}

Node JS HTTP GET request body

I am using the express module in node.js and I am trying to read the body of an HTTP GET request and send an answer back to the user based on the content of the body. I am new to node.js and this is not working for me.
I know I should be using HTTP POST for this (and it works when I am using post), but the server I am trying to mimic in node.js uses GET, so I have to stick to it. Is there a way to do this in node.js? Thanks!
Here is a sample code I did. When I use app.post, I see the logs for the body, but when I use app.get, I see no logs at all!
app.get('/someURL/', function(req, res){
var postData = '';
req.on('data', function(chunk) {
console.log("chunk request:");
console.log(chunk);
postData += chunk;
});
req.on('end', function() {
console.log("body request:");
console.log(postData);
});
//Manipulate response based on postData information
var bodyResponse = "some data based on request body"
res.setHeader('Content-Type', 'application/json;charset=utf-8');
res.setHeader('Content-Length', bodyResponse.length);
res.send(bodyResponse);
};
The version of Node's HTML parser you are using does not support bodies in GET requests. This feature is available on the latest unstable v0.11 branch.
https://github.com/joyent/node/issues/7575
https://github.com/joyent/node/issues/5767

Creating a simple Node.js web service for use with AJAX

I have a basic Node.js http server set up as per the docs, I'm trying to create a very simple web service I can talk to with Javascript (AJAX) which I'll then hook up to Arduino. It's a test piece, I may go down the road of something else but this is proving to be fun. Anyway, here is the server-side javascript:
var http = require('http');
var _return = 'Bing Bong';
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'application/jsonp'});
//do stuff
res.end('_return(\'Hello :-)\' + _return)');
}).listen(process.env.VMC_APP_PORT || 1337, null);
And this is the client side:
function experimentFive(node) {
console.log('X5 Func started');
console.log('Calling Node.js service');
var nodeURL = node;
$.ajax({
url: nodeURL,
dataType: "jsonp",
jsonpCallback: "_return",
cache: false,
timeout: 50000,
success: function(data) {
console.log('Data is: ' + data);
$("#nodeString").text(" ");
$("#nodeString").append(data);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log('error : ' + textStatus + " " + errorThrown);
}
});
}
experimentFive('http://fingerpuk.eu01.aws.af.cm/');
This works, I get the data back but not as I'd expect. What I'd like to be able to do is change some data server side and receive that back. I get back the string in the res.end plus:
function () {
responseContainer = arguments;
}
Instead of the variable's data. No matter how I try to get that data back, it is either undefined or this response.
From research I think the variable is not having it's data set before the callback fires, so it's empty. But if I set an initial value the data is still undefined.
Am I missing something very simple here? Should I just go back to C#?
Cheers.
One possible way of accomplishing this would be to use ExpressJS with NodeJS to handle routing your endpoints. By doing this you can set up routes such as GET /media/movies/, fire an AJAX request to this route, then have it return JSON data that you can handle on your app.
Here's an example of ExpressJS routing in an app that I made:
var groups = require('../app/controllers/groups');
// find a group by email
app.post('/groups/find', groups.searchGroupsByEmail);
Here is a great tutorial that I used when getting started with Express. It walks through the entire process from installing Node.JS (which you've already done) to setting up the ExpressJS routing to handle incoming HTTP requests.
Creating a REST API using Node.js, Express, and MongoDB

Categories

Resources