NodeJS: fetching ISO-8859-1-encoded url endpoints - javascript

I am trying to implement this (.net) example in Node.js using request and iconv-lite (its an HTTP web service that requires url requests are encoded in ISO-8859-1):
WebClient wc = new WebClient();
var encoding = Encoding.GetEncoding("iso-8859-1");
var url = new StringBuilder();
url.Append("https://url.com?");
url.Append("&param=" + HttpUtility.UrlEncode(foo, encoding));
wc.Encoding = encoding;
return wc.DownloadString(url.ToString());
The problem is with encoding the URL (doesnt work). I am trying to do the same GET request, in which the URL must be encoded as ISO-8859-1. However, by doing something like this:
var options = {
url : iconv.encode(url, 'ISO-8859-1').toString(),
method: 'get',
headers : {
'Content-Type': 'application/x-www-form-urlencoded; charset=ISO-8859-1'
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body);
}else {
console.log('err: ' + error);
}
});
It's still not sent as a ISO-8859-1 string. Any clues on how to get this to work like with the .NET example?

I think it's decoding the response, not encoding the url. Try this:
var https = require('https'),
qs = require('querystring');
// ...
var url = 'https://url.com/?' + qs.stringify({ param: 'foo' });
https.get(url, function(res) {
if (res.statusCode === 200) {
var bufs = [], bufsize = 0;
res.on('data', function(data) {
bufs.push(data);
bufsize += data.length;
}).on('end', function() {
var buffer = Buffer.concat(bufs, bufsize),
body = iconv.decode(buffer, 'iso-8859-1');
console.log('Body: ' + body);
});
return;
} else
console.log('Non-OK status code: ' + res.statusCode);
res.resume();
});

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()
});

Undefined value in the response when sending JSON object to the client- Node.js

I am new to Node.js and JavaScript and I was hoping to get some help after searching and being unable to find a solution.
I am trying to send a JSON object to the Node.js server containing an array of 2 elements (longitude and latitude) using the XMLHttpRequest method. This is the Client-side JavaScript code:
function getLocation() {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var location = [position.coords.latitude, position.coords.longitude];
console.log(location);
var xhr = new XMLHttpRequest();
xhr.open('POST', 'http://localhost:3000/locationdata', true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.onload = function () {
console.log(this.responseText);
};
xhr.send(location);
});
} else {
console.log('Geolocation is not supported by this browser.');
}
}
The server receives the object without any issue. However, when I try to send the object back to the client, I get an undefined value as the response. Here is the Node.js script:
var html =
fs.readFile(__dirname + '\\public\\index.html', function(err, data) {
if (err){
throw err;
}
htmlFile = data;
});
var server = http.createServer(function (request, response) {
if (request.url == "/") {
response.writeHead(200, {"Content-Type": "text/html"});
response.write(htmlFile);
break;
};
if (request.method == 'POST' && request.url == "/locationdata") {
var postdata = '';
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function() {
var postdata = body;
console.log(postdata);
});
response.writeHead(200, {"Content-Type": "application/json"});
response.write(JSON.stringify(postdata));
}
response.end();
});
server.listen(3000);
It might be that I am sending the response before the actual request has ended but I am not sure. Any ideas?
You are not waiting for the request data before responding, which causes you to respond with nothing. Do this instead:
if (request.method == 'POST' && request.url == "/locationdata") {
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function() {
response.writeHead(200, {"Content-Type": "application/json"});
response.end(body);
});
return;
}

How do I read Ajax parameter value in Node without framework?

I am trying to pass a variable to my Ajax send and read it in Node without using a framework. I am not trying to return the value back to the DOM, I just need to read the value passed to Node.js. Here is what I have:
Ajax:
const XHR = new XMLHttpRequest();
XHR.open('POST', document.url, true);
XHR.setRequestHeader('X-Requested-load', 'XMLHttpRequest2');
XHR.send(`password=${password}`);
Nodejs:
const QS = require('querystring');
let password = QS.parse(req.body);
req.on('data', (data) => {
password = QS.parse(data);
});
console.log(password);
Hope this will help you:
http.createServer(function (request, response) {
if (request.method == 'POST') {
// save all data received
var postdata = '';
// receiving data
request.on('data', function(chunk) {
postdata += chunk;
// Avoid too much POST data
if (postdata.length > 1e6)
request.connection.destroy();
});
// received all data
request.on('end', function() {
var post = qs.parse(postdata);
// handle post by accessing
// post['password']
// response.send(process(post['password']));
});
} else {
console.log("Non POST request received at " + request.url);
}
}).listen();
In your example you are trying to access password out of the callback where this data is provided.
const QS = require('querystring');
let password = QS.parse(req.body);
req.on('data', (data) => {
password = QS.parse(data);
//async. access data here
console.log(password);
});

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");

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