Problem i am solving:
Write an HTTP server that receives only POST requests and converts incoming POST body characters to upper-case and returns it to the client.
Your server should listen on the port provided by the first argument to your program.
My Solution
var http = require('http');
var map = require('through2-map')
http.createServer(function(request,response){
if (request.method == 'POST'){
request.pipe(map(function (chunk) {
return chunk.toString().toUpperCase();
})).pipe(response);
}
}).listen(process.argv[2]);
Can i implement is without using through2-map ?
My crippling solution which doesn't work:
request.on('data',function(data){
body += data.toString();
console.log(body);
});
request.pipe(body.toUpperCase()).pipe(response);
Can i do the real hard way ?
In the 2nd snippet, body.toUpperCase() will act immediately before any of the 'data' events have actually occurred. The call to .on() only adds the event handler so it will be called, but doesn't yet call it.
You can use the 'end' event, along with 'data', to wait for all data chunks to be received, ready to be uppercased:
request.on('data', function (data) {
body += data.toString();
});
request.on('end', function () {
response.end(body.toUpperCase());
});
Note: Be sure that body is being declared and assigned an initial value:
var body = '';
response.on('data', ...);
// ...
Related
I created an ajax call to the IMBd database
// API Key
key = "4dba72b2-7558-4c0f-bd18-9ffcb0999c4e";
// Url
mainUrl = "http://api.myapifilms.com/imdb/top?token="+ key +"&format=json&data=0&start=1&end=250";
// API Call
var request = require('request');
request(mainUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Storing data in an object
var obj = JSON.parse(body), //JSON Parser
movieArray = obj.data.movies, //Creating Array
item = movieArray[randomMovieRank]; //Setting random movie variable
itermArray = [item.ranking,item.title,item.year];
console.log(itermArray);
io.sockets.emit("serverAnswer", {ranking: itermArray[0], title: itermArray[1], year: itermArray});
}
});
return false;
Followed up by:
socket.on("serverAnswer", function(data){
console.log(data.title);
});
The socket.on is called on the client side. The problem I am having is that it is pulling through the data very slowly if at all. The API is working as it is console logging correctly in terminal. But client side it sometimes pulls through ad sometimes doesnt. Is there something I am doing wrong?
EDIT:
Added pastebin: http://pastebin.com/TYHsqBmK
When you invoke the emit method, your client is not guaranteed connected,you can trigger the ajax event after the client connected or emit specified messages,such as
the server:
io.on('connection',function(socket){
if(movies !== null)
{
socket.emit("serverAnswer", {movies:movies});
}
else{
//1.ajax request IMDB resource
//2.set movies variables
//3.emit message
}
});
the client:
socket.on("serverAnswer", function(data){
console.log(data);
});
I am using Node JS HTTP request. When my response length exceeds 16101 , it truncates my response. And I recieve limited response like this:
{"id_user":"133696"},{"id_u
This is not a chunked response, its only comes once. I want to recieve the whole response instead of truncated .
My Node version is v0.10.36.
Here is my code:
var https = require('https');
var querystring = require('querystring');
postData.format = 'json';
postData.apikey = 'abcd';
jsonObject = querystring.stringify(postData);
var postheaders = {
'Content-Type' : 'application/x-www-form-urlencoded',
'Content-Length' : Buffer.byteLength(jsonObject, 'utf8')
};
if(callMethod == undefined){
callMethod = 'POST';
}
var optionspost = {
host : this.host,
port : this.port,
path : this.path,
method : callMethod,
headers : postheaders
};
var reqPost = https.request(optionspost, function(res) {
res.setEncoding('utf-8');
res.on('data', function(responseData) {
//---->>> responseData containes truncated response
if(callFunction != undefined && callFunction != null && callFunction != ''){
callFunction(responseData, relatedData);//****** calling success function ****
}
});
res.on('end', function() {
});
});
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
Your code is expecting the data event only once, but Node can fire it more than once. In fact, it can fire it as many times as it damn pleases.:) Every time a data event is emitted, another part of the data is provided to you. You know that there is no more data to be consumed when the end event is fired - that's where you should process the data and/or call your callbacks.
Since the response is basically a readable stream, have a look at the data event for Readable Stream.
I want to use app.get to deliver the data from an API on another domain. I can write the data to the console, but nothing is appearing on the page ('~/restresults').
This is the code I have so far:
app.get('/restresults', function (req, res) {
var theresults;
var http = require('http');
var options = {
port: '80' ,
hostname: 'restsite' ,
path: '/v1/search?format=json&q=%22foobar%22' ,
headers: { 'Authorization': 'Basic abc=='}
} ;
callback = function(res) {
var content;
res.on('data', function (chunk) {
content += chunk;
});
res.on('end', function () {
console.log(content);
theresults = content ;
});
};
http.request(options, callback).end();
res.send(theresults) ;
});
how can I bind the result of the http.request to a variable and return it when 'restresults/' is requested?
Move res.send(theresults); to here:
callback = function(res2) {
var content;
res2.on('data', function (chunk) {
content += chunk;
});
res2.on('end', function () {
console.log(content);
theresults = content ;
res.send(theresults) ; // Here
});
};
Note: You'll have to change res to something else as you want the express res, no the request res.
The callback is an asynchronous call. You're sending the response before you get a result from the request.
You'll also want to handle the case in which there is an error, otherwise the client's request may hang.
You are currently sending the response before the callback (from the http request) is done.
The http.request is async, the script will not wait til its done and then send the data back to client.
You will have to wait for the request to be done and then send the result back to the client (preferably in the callback function).
Example:
http.request(options, function(httpRes) {
// Notice that i renamed the 'res' param due to one with that name existing in the outer scope.
/*do the res.on('data' stuff... and any other code you want...*/
httpRes.on('end', function () {
res.send(content);
});
}).end();
OK, I must be dense since I cannot find anywhere how to get the error status codes when using Node.JS http.get or http.request.
My code:
var deferred = $q.defer();
var req = https.get(options, function(response) {
var str = '';
response.on('data', function(chunk) {
str += chunk;
});
response.on('end', function() {
console.log("[evfService] Got user info: " + str);
deferred.resolve(str);
});
});
req.on('error', function(e) {
deferred.reject(e);
});
In that "req.on" bit, what I want is the http status code (i.e. 401, 403, etc.). What I get is a semi-useless error object that does not give me the code or any reference to the response object.
I have tried intercepting in the function(response) callback, but when there is a 404, it never gets called.
Thanks!
Your callback gets called regardless of the response status code from the server, so within your callback, check response.statusCode. That is, a 4xx status code isn't an error at the level you're working at; the server responded, it's just that the server responded by saying the resource wasn't available (etc.)
This is in the documentation but characteristically vague. Here's the example they give, with a comment pointing to the relevant bit:
var https = require('https');
https.get('https://encrypted.google.com/', function(res) {
console.log("statusCode: ", res.statusCode); // <======= Here's the status code
console.log("headers: ", res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
}).on('error', function(e) {
console.error(e);
});
If you try that with (say) an unknown resource, you'll see statusCode: 404.
So for what you're doing, you may want something like this:
var deferred = $q.defer();
var req = https.get(options, function (response) {
var str = "";
if (response.statusCode < 200 || response.statusCode > 299) { // (I don"t know if the 3xx responses come here, if so you"ll want to handle them appropriately
response.on("data", function() { } ); // ¹
deferred.reject(/*...with appropriate information, including statusCode if you like...*/);
}
else {
response.on("data", function (chunk) {
str += chunk;
});
response.on("end", function () {
console.log("[evfService] Got user info: " + str);
deferred.resolve(str);
});
}
});
req.on("error", function (e) {
deferred.reject(/*...with appropriate information, but status code is irrelevant [there isn"t one]...*/);
});
¹ The empty data event handler in the branch handling non-OK status codes is there because of this note in the documentation:
...if a 'response' event handler is added, then the data from the response object must be consumed, either by calling response.read() whenever there is a 'readable' event, or by adding a 'data' handler, or by calling the .resume() method. Until the data is consumed, the 'end' event will not fire. Also, until the data is read it will consume memory that can eventually lead to a 'process out of memory' error.
Since we're passing a function to https.get, we're hooking the 'response' event, which suggests we need to do one of those things (in this case, I've added a do-nothing data handler). Thanks to Nicolas2bert for pointing that out!.
An error code 400 response is not considered an error by node.js.
Try response.statusCode in this:
request.on('response', function (response) {});
Here's a very small example how to get the error code. Just change the https to http and create an error:
var https = require('https')
var username = "monajalal3"
var request = https.get("https://teamtreehouse.com/" + username +".json", function (response) {
console.log(response.statusCode);
});
request.on("error", function (error) {
console.error(error.status);
});
My server.js is
// server.js - the outer server loop
var http = require('http')
, php = require("./phpServer");
function start() {
function onRequest(request, response) {
php.phpServer('D:/websites/coachmaster.co.uk/htdocs',request, response);
response.write('Ending');
response.end();
}
http.createServer(onRequest).listen(80);
console.log("Server started.");
}
exports.start = start;
That calls php.phpServer every request with response as the 3rd param.
phpServer contains.
//
// phpServer.js - a generic server to serve static files and
//
var fs = require('fs')
, pathfuncs = require('path')
, url = require('url')
, mimetypes = require('./mimetypes')
function phpServer(root, request, response) {
// serve static or pass to php.
var data = url.parse(request.url);
var ext = pathfuncs.extname(data.pathname);
fs.stat(root+request.url, function(err, stat) {
if (err || !stat.isFile()) { // error or not file.
console.log('404');
response.writeHead(404);
response.write('Not Found');
return;
}
// exists - serve.
console.log("serve("+root+request.url+", mimetypes.mimetype("+ext+"))");
response.writeHead(200, {'Content-Type': mimetypes.mimetype(ext)});
response.write('Somethign to serve');
// fs.createReadStream(root+request.url).pipe(response);
});
}
exports.phpServer = phpServer
As I see it, response is an object and is passed by reference, therefore the response.write() here should write to the response.
It doesn't. Response here is NOT the same as response in onRequest, so nothing in phpServer is sent to the browser - not code nor content.
The console.logs come out and show what I would expect.
How can I get the object response passed so I can call write on it?
------------- added later -------------------
I've tried to apply answers given and code for server.is now
// server.js - the outer server loop
var http = require('http')
, fs = require('fs')
, pathfuncs = require('path')
, url = require('url')
, mimetypes = require('./mimetypes')
function phpServer(root, request, res) {
// code adapted from page 118 of Smashing Node.js by Guillermo Rauch
// res is response provided to onRequest.
var data = url.parse(request.url);
var ext = pathfuncs.extname(data.pathname);
res.write('Start reply');
fs.stat(root+request.url, function(err,stat) {
// define delayed callback - reponse in scope
if (err || !stat.isFile()) { // error or not file.
console.log('404');
res.writeHead(404);
res.write('Not Found');
res.end
return;
};
// exists so serve.
console.log("serve("+root+request.url+", mimetypes.mimetype("+ext+"))");
res.writeHead(200, {'Content-Type': mimetypes.mimetype(ext)});
res.write('The file contents');
res.end;
} // end callback,
); // end fs.stat call.
} // end phpServer
function start() {
function onRequest(request, response) {
phpServer('D:/websites/coachmaster.co.uk/htdocs',request, response);
}
http.createServer(onRequest).listen(80);
console.log("Server started.");
}
exports.start = start;
This does not reply at all - it times out. However the call to res.writeHead will either
fail, if res is out of scope/does not exist/undefined, or succeed if re is the param passed in.
It succeeds, and is followed by write and end, so please - what have I got wrong.
If the file does not exist I get a start reply and then a timeout.
At the res.write('Start reply'); res is the response param, yet it isn't later in the fs.stat call-back.
Why not?
Damn - this is frustrating.
The call to response.end should be moved from the onRequest function to phpServer. As it stands phpServer cannot write anything else since the stream has been closed.
function onRequest(request, response) {
php.phpServer('D:/websites/coachmaster.co.uk/htdocs',request, response);
// response.end(); // move this to phpServer
}
As explained in the documentation for response.end
This method signals to the server that all of the response headers and body have been sent; that server should consider this message complete.
Your problem is not with parameter passing, it's with basic asynchronous control flow. The stat() function does not do its work immediately. Its callback parameter is called when it's done. You basically cannot structure the code the way you've done it. Instead, your "phpServer" code will need to take a callback parameter of its own, and call it after it does its work.