Changing json on express node.js server - javascript

I'm quite new to node.js and web development in general (so if I'm entirely off base and you have good material for me to consume I'd really like to see it).
I'm trying to prototype passing a JSON object back and forth between node.js server and http client. The client side so far looks like:
<script type="text/javascript">
document.getElementById("myBtn").addEventListener("click", passArg);
function passArg() {
console.log("I'm here")
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", "/", true);
xmlhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == XMLHttpRequest.DONE ) {
if (xmlhttp.status == 200) {
//var json = JSON.parse(xmlhttp.responseText);
}
else if (xmlhttp.status == 400) {
alert('There was an error 400');
}
else {
alert('something else other than 200 was returned');
}
}
}
var data = JSON.stringify({"email":"hey#mail.com","password":"101010"});
xmlhttp.send(data);
get_json();
}
function get_json(){
console.log("getting json");
var xmh = new XMLHttpRequest();
xmh.open("GET", "/playlist/playlist.json", true);
xmh.send();
xmh.onreadystatechange = function() {
if (this.readyState == this.DONE ) {
if (this.status == 200) {
var json = JSON.parse( this.responseText );
console.log(json.email + " "+ json.password + " " + json.access_date);
}
else if (xmh.status == 400) {
alert('There was an error 400');
}
else {
alert('something else other than 200 was returned');
}
}
}
}
</script>
And the server side is coded as
app.post("/", function (req, res) {
console.log('Request received');
req.on('data', function (chunk) {
console.log('GOT DATA!');
json = JSON.parse(chunk);
json.access_date = "12.04.17";
write_json(json)
console.log("finished writing- in app_post")
});
console.log("passing all clear to client")
res.writeHead(200);
res.send();
})
function write_json(chunk){
console.log("WHADDUP")
console.log(JSON.stringify(chunk))
fs = require("fs")
var filename = "./public/playlist/playlist.json";
var file = require(filename);
file = chunk;
fs.writeFile(filename, JSON.stringify(file), function(err){
if (err) return console.log(err);
console.log(JSON.stringify(file));
console.log('writing to ' + fileName);
}
)
console.log("finished writing - in write_json")
}
On the serverside console the following output is generated
Request received
passing all clear to client
GOT DATA!
WHADDUP
{"email":"hey#mail.com","password":"101010","access_date":"12.04.17"}
module.js:428
throw err;
^
SyntaxError: public/playlist/playlist.json: Unexpected end of input
And on the client side of things the console reads
(index):15 I'm here
(index):41 getting json
(index):45 GET http://localhost:8080/playlist/playlist.json net::ERR_CONNECTION_RESET
From this I read that the asynchronous POST event is sending the all clear to call get_json before the file itself is updated. And it seems the updating of the file on the server side isn't working as well. How do I structure the calls to make the edit quite smooth?

The quick answer is to create a function to call res.send, pass it to your write_json function, and invoke it from inside your writeFile callback.
app.post("/", function (req, res) {
console.log('Request received');
req.on('data', function (chunk) {
...
write_json(json, function() {
console.log("passing all clear to client")
res.writeHead(200);
res.send();
console.log("finished writing")
});
});
});
function write_json(chunk, onFinishedWriting){
...
fs.writeFile(filename, JSON.stringify(file), function(err){
if (err) {
return console.log(err);
}
else {
console.log(JSON.stringify(file));
console.log('writing to ' + fileName);
onFinishedWriting();
}
});
}
However when you find yourself writing code like this:
});
});
});
then you are probably in the proverbial "callback hell". I suspect that what you want is to use promises. Here's a question specifically about promises and writeFile that will probably help you.

Related

NodeJS Lambda function returns null while still waiting for callback

Problem: I have a Lambda function written in NodeJS, simplified version below, which is meant to make a post to a specific URL to get a value in the body of the response. Then I'd like it to do something with that value in functionB, however, the function returns null while waiting for the callback from functionA.
Also, I'm new to NodeJS but I have tried to research this as much as I could before turning to you guys for help, if you find a question that this is a duplicate of, please direct me towards it with a little guidance as I may have come across it before without knowing why it's the same as my problem. Any help is greatly appreciated!
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
exports.handler = (event, context, callback) => {
functionA(event.payload, function(err, data) {
if(data) {
console.log(data);
valueB = data;
functionB(valueB, function(err, data) {
if(err) {
console.error('Unknown Error');
} else {
console.log(data);
callback(null, successMessage);
}
});
} else {
console.error('Unknown Error');
}
});
}
function functionA(payload, callback) {
var xmlhttp = new XMLHttpRequest();
var result;
// new HttpRequest instance, in the real code storedURL has been set
xmlhttp.open("POST", storedURL, true);
console.info("Linking to: ", storedURL);
xmlhttp.onload = function () {
console.log('Entering onload function');
if (xmlhttp.readyState === xmlhttp.DONE) {
console.log('readyState done');
if (xmlhttp.status === 200) {
console.log('status 200');
// console.log(xmlhttp.responseText);
var data = xmlhttp.responseText;
//console.log(data);
callback(null, data);
} else {
console.log('error');
console.log(xmlhttp.response);
callback("error in callback");
}
} else {
console.log('error');
}
};
xmlhttp.send(payload);
}
function functionB(valueB, callback) {
//Do something with valueB
callback(null, successMessage);
}

Nodejs - Response of POST request is undefined

I'm learning nodejs, and made a simple site to learn to handle POST requests.
Here is my code:
Browser-side:
function sendRequest (params) {
var xhr = new XMLHttpRequest();
var url = 'result';
xhr.open("POST",url,true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.onreadystatechange = function () {
console.log('onreadystatechange');
if(xhr.readyState == 4 && xhr.status == 200){
console.log('Response text:' + xhr.reponseText);
}
}
xhr.send(params);
}
Server-side:
else if (req.url === '/result') {
req.on('data', function (data) {
var params = data.toString().split('&');
var result = calc(params);
console.log(result.toString());
res.writeHead(200,{'Content-Type':'text/plain'});
res.write('<div>'+result.toString()+'</div>');
res.end();
console.log('Response over');
});
}
When i run this,xhr.responseText is undefined, and i'm having trouble understanding where the error is.
Based on the log, node gets the request, the result is correct,and xhr.onreadystatechange also runs(but xhr.responseText is undefined).
There is typing error in your browser side code. You misspelled responseText.
console.log('Response text:' + xhr.responseText);

fibers not working in meteor react - Error: Meteor code must always run within a Fiber

I am using fibers in meteor + react on server side. I have created an api (using nimble:restivus package of atmospherejs) but I am getting an error on server's log
var response = {}; var url = //any server url var Future = Npm.require( 'fibers/future' ); var future = new Future(); xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
data = JSON.parse(xhttp.responseText);
console.log(data.status," -- responseText cancel image preview job -- ", xhttp.responseText," jobId -- ",id)
if(data.status == "success"){
console.log('success')
mongoCollection.update({_id:id},{
$set:{
status: "cancel"
}
},(err)={
if(err) {
console.log("error")
response.status = "error";
response.message = err;
future.return( response);
}
else{
response.status ="success";
future.return( response);
}
})
}else {
console.log("not success")
response.status = data.status;
response.message = data.message;
future.return( response);
}
} }; xhttp.open("POST", url); xhttp.setRequestHeader('Content-Type', 'application/json'); xhttp.send(JSON.stringify(json));
I am getting following error:
[Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.]
Try this:
//...
xhttp.onreadystatechange = Meteor.bindEnvironment(function() {
//your function code goes here...
});
//...

turn caching off in javascript

Hi all I am trying to turn caching off by
Adding a random value to the query string component of the URL sent with the request message.
I have a server that sends the etag as a string to my client and I want to make sure no caching is going on I already setRequestHeaders but i'm also supposed to add an http request similar to POST /message?x=0.123456789 HTTP/1.1
this is my client code
<html>
<header><title>This is title</title></header>
<body>
<span id="ajaxButton" style="cursor: pointer; text-decoration: underline">
Make a request
</span>
<script type="text/javascript">
(function() {
var httpRequest;
var x= Math.random();
document.getElementById("ajaxButton").onclick = function() { makeRequest('http://localhost:5000/'); };
function makeRequest(url) {
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
}
if (!httpRequest) {
alert('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
httpRequest.onreadystatechange = alertContents;
httpRequest.open('GET', url, true);
//httpRequest.setRequestHeader("pragma", "no-cache");
//httpRequest.setRequestHeader("Cache-Control", "no-cache", "no-store");
httpRequest.send();
}
function alertContents() {
if (httpRequest.readyState === 4) {
if (httpRequest.status === 200) {
var etagString = httpRequest.responseText;
alert(etagString);
} else {
alert('There was a problem with the request.');
}
}
}
})();
</script>
</body>
</html>
edit for adding errors
XMLHttpRequest cannot load http://localhost:5000/?_0.1909303846769035. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
using node.js I run the server using main.js which is
var http = require('http');
var domain = require('domain');
var root = require('./root'); // do I have to replace root w/ message
var image = require('./image'); // for better readability?
function replyError(res) {
try {
res.writeHead(500);
res.end('Server error.');
} catch (err) {
console.error('Error sending response with code 500.');
}
};
function replyNotFound(res) {
res.writeHead(404);
res.end('not found');
}
function handleRequest(req, res) {
console.log('Handling request for ' + req.url);
if (req.url === '/') {
root.handle(req, res);
}
if (req.url === '/image.png'){
image.handle(req, res);
}
else {
replyNotFound(res);
}
}
var server = http.createServer();
server.on('request', function(req, res) {
var d = domain.create();
d.on('error', function(err) {
console.error(req.url, err.message);
replyError(res);
});
d.run(function() { handleRequest(req, res)});
});
function listen(){
server.listen(5000);
}
root.init(listen);
and inside root.js is
var http = require('http');
var response = require('./response');
var body;
var etag;
exports.handle = function(req, res) {
if (req.headers['if-none-match'] === etag) {
console.log('returning 304');
return response.replyNotModified(res);
}
res.writeHead(200, {'Content-Type': 'text/plain',
'Content-Length': body.length,
"Access-Control-Allow-Origin":"*",
"Access-Control-Allow-Headers":"X-Requested-With",
'ETag' : etag
});
res.end(body);
}
exports.init = function(cb) {
require('fs').readFile('app.html', function(err, data) {
if (err) throw err;
etag = response.generateETag(data); //
body = etag;
console.log("init");
cb();
});
}
/*function generateETag(buffer) {
var shasum = require('crypto').createHash('sha1');
shasum.update(buffer, 'binary');
return shasum.digest('hex');
console.log(shasum.digest('hex'));
}
var replyNotModified = function(res) {
res.writeHead(304);
res.end();
};*/
the errors are in
So, the error that you're getting is to do with cross-origin resource sharing, which has nothing to do with caching or query strings. It looks like you're trying to make AJAX calls from a file:// url, which you can't do.
If you serve the page in question from your Node.js app, that message should go away.
If you can't do that, set up that app to send CORS headers. You can read about CORS in detail at MDN, but the short version is that you need to send a header that looks like this (where otherdomain.com is where the Web page is hosted):
Access-Control-Allow-Origin: http://otherdomain.com
Note that you'll still have to serve the page over HTTP; to my knowledge you can't do AJAX at all from a page loaded via a file:// URL.
You could add '_=' + new Date().getTime(); to the query string of the url. Since it isn't clear whether the url already has a query string attached to it, it's hard to give a more complete answer. It'd be either url += '?_=' + new Date().getTime(); or url += '&_=' + new Date().getTime();.
I'll leave this answer here because it seems to answer the question that the OP was asking. But the solution to the problem the OP was experiencing is Adam Brenecki's answer below.

Is it possible to catch the exception generated by trying to connect to a bad url?

using node http package it doesn't seem possible to catch the exception caused by opening a bad URL. This is a problem, because it kills my cluster, which I'd like to guarantee will live forever
Here's the code: (uses fibers.promise)
function openConnection(dest, port, contentType, method, throwErrorOnBadStatus)
{
"use strict";
assert.ok(dest, "generalUtilities.openConnection: dest is null");
//dest = dest.replace('//','/');
console.log('opening connection: ' + dest + " contentType: " + contentType);
var prom = promise(),
errProm = promise(),
ar = [],
urlParts = url.parse(dest),
httpClient,
req,
got,
res;
//console.log('urlParts.port: ' + urlParts.port);
if (port) {
urlParts.port = port;
} else if (!urlParts.port) {
urlParts.port = 80;
}
if (contentType) {
urlParts.accept = contentType;
} else {
urlParts.contentType = 'text/html';
}
if (!urlParts.method) {
if (method) {
urlParts.method = method;
} else {
urlParts.method = 'GET';
}
}
try {
httpClient = http.createClient(urlParts.port, urlParts.hostname);
req = httpClient.request(urlParts.method, urlParts.path, urlParts);
//console.log('req: ' + req);
//if (req.connection) {
// req.connection.setTimeout(HTTP_REQUEST_TIMEOUT);
//}
//else {
// throw new Error ("No Connection Established!");
//}
req.end();
req.on('response', prom);
req.on('error', errProm);
got = promise.waitAny(prom, errProm);
if (got === errProm) {
//assert.ifError(errProm.get(), HTTP_REQUEST_TIMEOUT_MSG + dest);
throw new Error(HTTP_REQUEST_TIMEOUT_MSG + dest + ': ' + got.get());
}
res = prom.get();
ar.res = res;
ar.statusCode = res.statusCode;
if (ar.statusCode >= 300 && throwErrorOnBadStatus) {
assert.ifError("page not found!");
}
return ar;
}
catch (err) {
console.log(err);
}
}
and here's how I tested it
var promise = require('fibers-promise');
var gu = require("../src/utils/generalutilities.js");
var brokenSite = 'http://foo.bar.com:94//foo.js';
promise.start(function () {
try {
gu.openConnection(brokenSite, null, null, "GET", true);
}
catch (err) {
console.log('got: ' + err);
}
});
When I run this code I get:
Error: getaddrinfo ENOENT. It is never caught in the try catch
It works for me, when supplying an error handler for the request:
req.on('error', errorHandler);
I see that you also do that, but you set it after issuing
req.end();
Could you try issuing the end() after you attached the error handler?
As a side note, I really recommend request, as it handles issues like this with sensible defaults. It's really a breeze to work with.
Edit: Here is a simple example showing that attaching an error handler lets me handle ENOENT/ENOTFOUND errors:
var http = require('http');
var req = http.request({hostname: 'foo.example.com'}, function(err, res) {
if(err) return console.error(err);
console.log('got response!');
});
req.on('error', function(err) {
console.error('error!', err);
});
Another piece of valuable information: I'm not sure how it fits in with fibers, but in general, you should never throw in nodejs asynchronous code. It rarely works the way you want. Instead, use the standard practice of passing any error as the first parameter to the next callback, and handle the error where it makes sense (usually, high up in the call chain where you can do something sensible with it).
You can scrape the page for the error code.

Categories

Resources