Requests bigger than 8 kb - javascript

I want to evaluate round trip time between client and server. Here the user can choose how big the request/response size of the message (body) should be. At client side I used Ajax-Post method to send 100 messages in an interval of 100 ms to the http-server. Unfortunatley I got the problem in node.js, that the httpServer.js cannot handle client request sizes of bigger than 8 kb. In this case the variable responseSizeServer in httpServer.js gets the value "undefined" and the console throw an error: "Invalid Array length". The question is why the variable responseSizeServer has got the value undefined ins this case? I suppose that the http-Server.js handle the .end method faster than the incoming request from the client. What do you think and how can it be solved? Thanks in advance :)
Here is the code:
client:
var i = 0;
var iterations = 100;
function connectSpeed(){
run = window.setInterval("startSpeed()", 100);
}
function startSpeed()
{
//Variablen
var requestSizeClient = 8 *1024; // 8 kb request Size client
var responseSizeServer = 16 * 1024; // 16 kb response size server
var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST","http://localhost:8000", true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.onreadystatechange=function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
var receiveTimeCl = new Date().getTime().toString();
//evaluate response from httpServer.js
var message = xmlhttp.responseText;
}
}
//send data to the server
xmlhttp.send(new Date().getTime().toString() + '#' + new Array((eval(requestSizeClient+1))-(new Date().getTime().toString().length+3)).join('X') + '#' + responseSizeServer);
i++;
if(i==iterations) {
window.clearInterval(run);
i=0;
}
}// end start-speed
server: (httpServer.js)
var http = require('http');
http.createServer(function (req, res) {
var receiveTimeServer;
var clientMsg;
var sendTimeClient;
var responseSizeServer;
var message;
req.on('data', function (chunk) {
receiveTimeServer = new Date().getTime().toString();
message = chunk.toString('utf8');
clientMsg = message.split('#');
responseSizeServer = parseInt(clientMsg[2]);
sendTimeClient = clientMsg[0];
res.writeHead(200, {'Content-Type': 'text/plain','Access-Control-Allow-Origin' : '*'});
res.end(receiveTimeServer + '#' + new Date().getTime().toString() + '#' + sendTimeClient + '#' + new Array(responseSizeServer).join('X'));
});
}).listen(8000);
console.log('Ajax_Server running');

Requests in Node.js are streams, and each data event corresponds to an incoming chunk. If the request is big, then multiple chunks are emitted: one can then handle a request while it is being sent, and don't have to wait for the full request to be received before handling it.
In your specific case, what you want is to buffer the full message and then handle it:
var message = '';
req.on('data', function (chunk) {
message += chunk; // concatenate all chunks
});
req.on('end', function() {
receiveTimeServer = new Date().getTime().toString();
message = message.toString('utf8');
clientMsg = message.split('#');
responseSizeServer = parseInt(clientMsg[2]);
sendTimeClient = clientMsg[0];
res.writeHead(200, {'Content-Type': 'text/plain','Access-Control-Allow-Origin' : '*'});
res.end(receiveTimeServer + '#' + new Date().getTime().toString() + '#' + sendTimeClient + '#' + new Array(responseSizeServer).join('X'));
});
You can find a thorough explanation with code samples in Node.js's streams documentation.

Related

How can a JS Client pass POST parameters to a JS Server?

I'd like to have a pair of Javascript client and server that communicate
using JSON without involving a Web Browser. I can get it going as long as
the client does not try to send anything to the server. When it does, I get
the error message (% node poster.js):
.../node_modules/xhr2/lib/xhr2.js:281
throw new NetworkError(`Unsupported protocol ${this._url.protocol}`);
Can somebody help me with this protocol issue please. What I have so far:
a server that I can start with "pm2 start jsonServer.js" -
var port = 62022
var http = require('http')
var srvr = http.createServer (function (req, res) {
console.log ('Request type: ' + typeof(req))
console.log (req)
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World!\n');
res.write(req);
res.end();
})
var scriptName = __filename.split(__dirname+"/").pop();
console.log ('Script: ' + scriptName +'. Listening to port ' + port)
srvr.listen(port)
... and a client that is
var XMLHttpRequest = require('xhr2')
var serialize = function(object) {
return JSON.stringify(object, null, 2)
}
let xhr = new XMLHttpRequest();
xhr.open("POST", "localhost:62022");
xhr.setRequestHeader("Accept", "application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onload = () => console.log(xhr.responseText);
let data = `{
"Id": 912,
"First Name": "Archibald",
"Last Name": "Haddock"
}`;
//console.log (serialize(data));
//xhr.send(serialize(data));
console.log (data);
xhr.send(data);
This is what is needed after posting 'Hello World!' on the server (res.end does not wait for the async data transfer):
let data = '';
req.on('data', chunk => {
data += chunk;
});
req.on('end', () => {
// do whatever with data
res.write ('Data: ' + data + '\n')
res.end()
});

How to get POST parameters via node.js

I a m kinda stuck. I made a request to a server. I want the server to computer a operation for me, and send me back the result.
Request :
ar http = require('http');
http.createServer(function(req, res){
var response = "Hello from " + req.client.remoteAddress + ":" + req.client.remotePort + "\n to " + req.client.localAddress + ":" + req.client.localPort;
console.log(response);
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const Http = new XMLHttpRequest();
console.log("start");
n = 15;
const urlfibo='http://172.22.0.4:8899';
Http.open("POST", urlfibo,false);
var params = 'value=15';
Http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
Http.send(params);
console.log(Http.responseText);
response += Http.responseText;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write(response);
res.end();
On my server, i don't know where to find the parameter i passed. I've tryed the solution in the doc, but my code is never running into it :
```
response += "\n ON" + req.on
let body = [];
req.on('data', (chunk) => {
response += "bla"
body.push(chunk);
}).on('end', () => {
body = Buffer.concat(body).toString();
// at this point, `body` has the entire request body stored in it as a string
});
My question is : on y server (second part of code), how do i get my params i passed when i sent the request ? I want to do it with nodejs without using frameworks
Thank you
chunk will have all informations because is an object, you just have to assign this values for a new object and look for the parameters. Bug make sure to have in your code:
const bodyParser = require('body-parser');
app.use(bodyParser);

node.js redirection not working to add username

I am working on a Team Treehouse project that builds a dynamic website with Node.js. The user enters in a username into the search field and it displays the user's avatar, number of badges earned and the number of JavaScript points. For some reason when I enter in the user name and click search the page just goes blank. I think there might be something wrong with the 303 redirection in my router.js file. I'm still fairly new to coding so any insight would be very helpful. Here are each of my js files.
/*****app.js file******/
var router = require('./router.js');
//Problem: We need a simple way to look at a user's badge count and JavaScript points from a web browser
//Solution: Use Node.js to perform the profile look ups and serve our templates via HTTP
//Create a web server
var http = require('http');
http.createServer(function (request, response) {
router.home(request, response);
router.user(request, response);
}).listen(3000);
console.log('Server running at http://<workspace-url>');
/*****router.js file******/
var Profile = require("./profile.js");
var renderer = require('./renderer');
var querystring = require('querystring');
var commonHeader = {'Content-Type': 'text/html'};
// Handle the HTTP route GET / and POST / i.e. Home
function home(request, response) {
//if url == "/" && GET
if (request.url === '/'){
if (request.method.toLowerCase() === "get") {
//show search
console.log(request.url);
response.writeHead(200, commonHeader);
renderer.view('header', {}, response);
renderer.view('search', {}, response);
renderer.view('footer', {}, response);
response.end();
}
else {
//if url == "/" && POST
//get the post data from body
request.on('data', function(postBody){
//extract the username
var query = querystring.parse(postBody.toString());
//redirect to /:username
response.writeHead(303, {'Location': '/' + query.username });
response.end();
});
}
}
}
// Handle the HTTP route for GET /:username i.e. /chalkers
function user(request, response) {
//if url == "/...."
var username = request.url.replace('/', '');
if(user.name.length > 0){
response.writeHead(200, commonHeader);
renderer.view('header', {}, response);
//get json from Treehouse
var studentProfile = new Profile(username);
//on "end"
studentProfile.on("end", function(profileJSON){
//show profile
//Store the values which we need
var values = {
avatarUrl: profileJSON.gravatar_url,
username: profileJSON.profile_name,
badges: profileJSON.badges.length,
javascriptPoints: profileJSON.points.JavaScript
}
//Simple response
renderer.view('profile', values, response);
renderer.view('footer', {}, response);
response.end();
});
//on "error"
studentProfile.on("error", function(error){
//show error
renderer.view('error', {errorMessage: error.message}, response);
renderer.view('search', {}, response);
renderer.view('footer', {}, response);
response.end();
});
}
}
module.exports.home = home;
module.exports.user = user;
/*****profile.js file*******/
var EventEmitter = require("events").EventEmitter;
var http = require("http");
var util = require("util");
/**
* An EventEmitter to get a Treehouse students profile.
* #param username
* #constructor
*/
function Profile(username) {
EventEmitter.call(this);
profileEmitter = this;
//Connect to the API URL (http://teamtreehouse.com/username.json)
var request = http.get("http://teamtreehouse.com/" + username + ".json", function(response) {
var body = "";
if (response.statusCode !== 200) {
request.abort();
//Status Code Error
profileEmitter.emit("error", new Error("There was an error getting the profile for " + username + ". (" + http.STATUS_CODES[response.statusCode] + ")"));
}
//Read the data
response.on('data', function (chunk) {
body += chunk;
profileEmitter.emit("data", chunk);
});
response.on('end', function () {
if(response.statusCode === 200) {
try {
//Parse the data
var profile = JSON.parse(body);
profileEmitter.emit("end", profile);
} catch (error) {
profileEmitter.emit("error", error);
}
}
}).on("error", function(error){
profileEmitter.emit("error", error);
});
});
}
util.inherits( Profile, EventEmitter );
module.exports = Profile;
/*****renderer.js file*******/
var fs = require('fs');
function mergeValues(values, content) {
//Cycle over the keys
for(var key in values) {
//Replace all the {{key}} with the value from the values object
content = content.replace('{{' + key + '}}', values[key]);
}
//return merged content
return content;
}
function view(templateName, values, response) {
//Read from the template file
var fileContents = fs.readFileSync('./views/' + templateName + '.html', {encoding: 'utf8'});
//Insert values in to the content
fileContents = mergeValues(values, fileContents);
//Write out the contents to the response
response.write(fileContents);
}
module.exports.view = view;
Treehouse changed from http to https and so this example code doesn't work any longer. The reason for that is in the profile.js file. You are making calls for an http site and it doesn't exist. You need to change the code (only in profile.js) to make it connect to the https site instead.
var http = require("http");
should be changed to
var https = require("https");
and with that all references to the variable in your profile.js code should be changed to https.
As well as the hard-coded URL start:
var request = http.get("http://teamtreehous...
should be
var request = https.get("https://teamtreehous...
That should resolve the problem. Good luck!
In order to get your code in the profile.js file to run, you need to change some instances of the "http" module to "https" but, and this is important, not all instances.
What needs to remain http is the the status code error on the profile.js page. This line of code is correct:
profileEmitter.emit("error", new Error("There was an error getting the profile for " + username + ". (" + http.STATUS_CODES[response.statusCode] + ")"));
But all other instances of the http module need to change to https. For example, these lines are correct:
var url = "https://teamtreehouse.com/" + username + ".json";
var request = https.get(url, function(response){
Remember to require both modules at the top of profile.js page
var http = require("http");
var https = require("https");

How can i make a response.write in the request module

I'm creating HTTP server and inside i'm sending a request to to yahoo finance website and getting some data from it, what i want to do is to print to browser the data i got from yahoo finance.
the thing is that response.write isn't working inside the request.
Here is my code:
var http = require('http');
var request = require('request');
var cheerio = require('cheerio');
var util = require('util');
var host = "127.0.0.1";
var port = 1400;
var server = http.createServer(function (req, res) {
//writing the headers of our response
res.writeHead(200, {'Content-Type':'text/plain'});
// Variable Deceleration
// TODO: move from the global scope
var ticker = "IBM";
var yUrl = "http://finance.yahoo.com/q/ks?s=" + ticker;
var keyStr = new Array();
//
// The main call to fetch the data, parse it and work on it.
//
request(yUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
var $ = cheerio.load(body);
// the keys - We get them from a certain class attribute
var span = $('.time_rtq_ticker>span');
stockValue = $(span).text();
res.write("trying to print something");
console.log("Stock - " + ticker + " --> text " + stockValue );
}
}); // -- end of request --
res.write('Welcome to StockWach\n');
//printing out back to the client the last line
res.end('end of demo');
});
server.listen(port, host, function () {
console.log("Listening : " + host +":" + port);
});
You have to end the response (res.end();). Almost all browsers buffer some number of bytes from the response before showing anything, so you won't see the trying to print something until the response has ended.
If you use something like cURL though, you will see the trying to print something right away before the response is ended.

Problem receiving response from node server using ajax post request

I have written a http server using node js
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs");
http.createServer(function(request, res) {
var parsed_url = url.parse(request.url);
var uri = parsed_url.pathname;
if(uri === "/test"){
res.writeHead(200, {'Content-Type': 'text/javascript'});
request.addListener('data', function (chunk) {
var data = eval("(" + chunk + ")");
console.log(data[0].id);
})
request.addListener('end', function() {
console.log('end triggered');
res.write("Post data");
res.end();
});
}
}).listen(8080);
and i am trying to send back response of ajax request but i am unable to receive any response. Here is the code for ajax request ,
var myhttp = new XMLHttpRequest();
var url = "http://localhost:8080/test";
var data = [{"a":"1"},{"b":"2"},{"c":"3"}];
var dataJson = JSON.stringify(data);
myhttp.open('POST', url, true);
myhttp.send(dataJson);
myhttp.onreadystatechange = function() {
if ((myhttp.readyState == 4) && (myhttp.status == 200)){
alert(myhttp.responseText);
}
else if ((myhttp.readyState == 4) && (myhttp.status != 200))
{
console.log("Error in Connection");
}
Can anyone help me what i am doing wrong ...
Thanks
Vinay
Your code is almost right but on your code sample you have
console.log(data[0].id)
the data object has no property id so if you only have
console.log(data[0])
there you have a response like
{ a: '1' }
therefore you can access the property a by doing
console.log(data[0].a);
UPDATED Updated with a full example
One more thing is that you are using eval and node comes with JSON.parse bundle with it so the snippet below is how i made it work
File: app.js
var sys = require("sys"),
http = require("http"),
url = require("url"),
path = require("path"),
fs = require("fs");
http.createServer(function(request, res) {
var parsed_url = url.parse(request.url);
var uri = parsed_url.pathname;
if(uri === "/test"){
res.writeHead(200, {'Content-Type': 'text/javascript'});
request.addListener('data', function (chunk) {
// removed this - eval("(" + chunk + ")");
var data = JSON.parse(chunk);
console.log(data[0].a);
})
request.addListener('end', function() {
console.log('end triggered');
res.write("Post data");
res.end();
});
} else if(uri === "/") {
fs.readFile("./index.html",function(err, data){
if(err) throw err;
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
});
}
}).listen(8080);
On the same directory create a file index.html with the following:
<html>
<head>
<script type="text/javascript" charset="utf-8">
var myhttp = new XMLHttpRequest();
var url = "http://localhost:8080/test";
var data = [{"a":"1"},{"b":"2"},{"c":"3"}];
var dataJson = JSON.stringify(data);
myhttp.open('POST', url, true);
myhttp.send(dataJson);
myhttp.onreadystatechange = function() {
if ((myhttp.readyState == 4) && (myhttp.status == 200)){
alert(myhttp.responseText);
}
else if ((myhttp.readyState == 4) && (myhttp.status != 200))
{
console.log("Error in Connection");
}
}
</script>
</head>
<body>
</body>
</html>
That is a complete working example of what you want.
With regards to the same origin policy issues you were having is mainly due to the fact that you cant POST data between 2 different domains via ajax unless you use some tricks with iframes but that is another story.
Also i think is good for anyone to understand the backbone of a technology before moving into frameworks so fair play to you.
good luck
You have to read the data in a different way. Posted data arrives on a node server in chunks (the 'data' event), that have to be collected until the 'end' event fires. Inside this event, you are able to access your payload.
var body = '';
request.addListener('data', function (chunk) {
body += chunk;
});
request.addListener('end', function() {
console.log(body);
res.write('post data: ' + body);
});
Additionaly, there seem to be some issues with your client-side code (especially concerning the status-code checks), but i can't really help you with those as i always work with frameworks like jQuery to manage async requests.
If you want to build reliable node.js servers for web use, i highly recommend the high-performance HTTP-Framework Express. It takes away alot of the pain when developing a web-based server application in node and is maintained actively.

Categories