In the following code, I want to read the parameters from the link and display them. I used two separate if statements to check each parameter. The problem is it only reads the first if statement and discards the second one (does not check the second parameter):
var http = require('http');
var url = require('url');
var server = http.createServer(function (request, response) {
if (request.method == 'GET') {
var queryData = url.parse(request.url, true).query;
response.writeHead(200, {"Content-Type": "text/plain"});
// if parameter is provided
if (queryData.name) {
response.end('Hello ' + queryData.name + '\n');
} else {
response.end("Hello World\n");
}
if (queryData.age) {
response.end('Your age is ' + queryData.age + '\n');
} else {
response.end("No age provided\n");
}
}
});
// Listen on port 3000, IP defaults to 127.0.0.1 (localhost)
server.listen(8081);
The link is:
http://127.0.0.1:8081/start?name=john&age=25
Do not use response.end. Instead use response.write and add an response.end() after both if-statements.
See docs: https://nodejs.org/api/http.html#http_response_write_chunk_encoding_callback
Try response.write in the first if block.
Related
I have a server file with a switch using the URL to display appropriate content. One of the cases is /users which should display a JSON string of a certain table. This is returned from a mysql file.
server.js
var http = require('http')
var url = require('url')
var port = 8080
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname
console.log('Request for ' + pathname + ' received.')
response.writeHead(200, {'Content-Type': 'text/html'})
response.write(run(pathname))
response.end()
}
function run(pathname) {
switch(pathname) {
case '/':
response = 'Welcome to my little test'
break
case '/time':
response = 'The time is ' + new Date().toLocaleTimeString()
break
case '/users':
var response
require('./mysql').getUsers(function(users) {
console.log(users)
response = users
})
return response
break
default:
response = 'Unable to locate the requested page'
}
return response
}
http.createServer(onRequest).listen(port)
console.log('Server started on port ' + port + '.')
mysql.js
var mysql = require('mysql')
var connection = mysql.createConnection({
user: "root",
password: "password",
database: "main"
})
exports.getUsers = function(callback) {
connection.query('SELECT * FROM users;', function (error, rows, fields) {
callback(JSON.stringify(rows));
});
};
The console.log(users) in server.js displays the JSON string fine, but I cannot figure out how to get the value out of the callback and into the response variable.
Any ideas will be greatly appreciated.
The way you could extract the value out of the callback is to assign that value to a variable out of the callback's scope, but I don't recommend you to do that since you would end up with lots of global variables, besides you don't know when the variable will be assigned. Try this and see what happens so you get some insight with how callbacks and node.js works:
function run(pathname) {
switch(pathname) {
case '/':
response = 'Welcome to my little test'
break
case '/time':
response = 'The time is ' + new Date().toLocaleTimeString()
break
case '/users':
var response
var out_of_callback_users
require('./mysql').getUsers(function(users) {
out_of_callback_users = users
console.log("In the callback")
console.log(users)
response = users
})
console.log("After require");
console.log(out_of_callback_users) //Users have not been assigned yet
setTimeout(function(){
console.log("In the timeout")
console.log(out_of_callback_users)
},5000) //After 5 secs the query has been completed and users have been assigned.
return response
break
default:
response = 'Unable to locate the requested page'
}
return response
}
The way I would go is something like this:
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname
console.log('Request for ' + pathname + ' received.')
response.writeHead(200, {'Content-Type': 'text/html'})
run(pathname, function(response){
response.write(response)
response.end()
})
}
function run(pathname,cb) {
switch(pathname) {
case '/':
cb('Welcome to my little test');
break;
case '/time':
cb('The time is ' + new Date().toLocaleTimeString());
break;
case '/users':
require('./mysql').getUsers(function(users) {
console.log(users);
cb(users);
})
break;
default:
cb('Unable to locate the requested page');
}
return;
}
http.createServer(onRequest).listen(port)
console.log('Server started on port ' + port + '.')
you can't do it like this. the problem is easy. let's talk about it:
function getUsers is an asynchronous. so the code follow runs like this:
case '/users':
var response
require('./mysql').getUsers(function(users) {
console.log(users)
response = users
})
return response
break
first, run require('./mysql').getUser() , then it will do return response directly, then break . when the getUser function is finished, it will run
function(users) {
console.log(users)
response = users
})
so, a rule you need to follow: once you use asynchronous, the other function have to be asynchronous.
i wonder you can modify like follow:
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname
console.log('Request for ' + pathname + ' received.')
response.writeHead(200, {'Content-Type': 'text/html'})
run(pathname, function(res){ response.write(res)}) //changed
response.end()
}
function run(pathname, callback) {
switch(pathname) {
case '/':
callback('Welcome to my little test')
break
case '/time':
callback('The time is ' + new Date().toLocaleTimeString())
break
case '/users':
var response
require('./mysql').getUsers(function(users) {
console.log(users)
callback(users) # changed
})
break
default:
callback('Unable to locate the requested page')
}
}
http.createServer(onRequest).listen(port)
console.log('Server started on port ' + port + '.')
You do not need to serialize the mysql returned rows to use it. Either you can process it within getUsers, or return it back to the controller. If you return it, change code to:
exports.getUsers = function(callback) {
connection.query('SELECT * FROM users;', function (error, rows, fields) {
callback(rows);
});
};
Now within the server.js file, you can process the returned rows, like:
case '/users':
var response = ''
require('./mysql').getUsers(function(users) {
for (var i in users) {
var user = users[i];
var userId = user.id;
var userName = user.user_name;
response += "User - ID: "+userId+" Name: "+userName+"\n";
}
})
return response;
break;
You can process
I am running a simple nodejs application using index, server, router and requestHandler and it shows an error as soon as the line response.writeHead(200,{"Content-Type":"text/html"}); is reached. The code is:
File requestHandler.js:
var querystring=require("querystring"),
fs=require("fs"),
formidable=require("formidable");
function start(response){
console.log("Request handler 'start' was called.");
var body='<html>'+
'<head>'+
'<meta http-equiv="Content-Type"'+
'content="text/html; charset=UTF-8"/>'+
'</head>'+
'<body>'+
'<form action="/upload" enctype="multipart/form-data"'+
'method="post">'+
'<input type="file" name="upload" mulitple="multiple">'+
'<input type="submit" value="Upload file"/>'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200,{"Content-Type":"text/html"});
response.write(body);
response.end();
}
File index.js:
var server= require("./server");
var router= require("./router");
var requestHandlers= require("./requestHandlers");
var handle={}
handle["/"]=requestHandlers.start;
handle["/start"]=requestHandlers.start;
server.start(router.route, handle);
File router.js:
function route(handle, pathname, request, response){
console.log("About to route request for "+pathname);
if (typeof handle[pathname] === 'function'){
handle[pathname](request, response);
}else{
console.log("No request handler found for" +pathname);
response.writeHead(404, {"Content-Type":"text/html"});
response.write("404 Not found");
response.end();
}
}
exports.route=route;
File server.js:
var http=require("http");
var url=require("url");
function start(route, handle){
function onRequest(request, response){
var pathname=url.parse(request.url).pathname;
console.log("Request for " + pathname + " received");
route(handle, pathname);
route(handle,pathname,response,request);
}
http.createServer(onRequest).listen(8888);
console.log("Server has started");
}
exports.start=start;
A few errors in your code that I would like to point out-
The RequestHandlers function start is not being exported. Hence, it is impossible for index.js to use that function. You need to add this firstly in your requestHandlers.js file
exports.start = start;
The next issue is in router.js. If the if condition is satisfied, you are calling the function pointed by the variable handle[pathname]. But you are passing two parameters- request and response. You do not need to pass the start function with request because- a) That function does not accept that as a parameter and b) You are not looking to gather anything for the request. If you do need to take some information from the request(a variable passed in the URL), you could add that parameter to start function and deal with it appropriately. But for now just remove that parameter when you call handle[pathname]. So, edit this line in router.js-
handle[pathname](response);
Finally, one very small problem in server.js. You are not passing the correct number of parameters in the first call to route. So remove route(handle,pathname). Secondly, in your second call, you swapped the two variables. You cannot do that with request and response because node.js looks for the variable reponse for the response to be outputted and request is for any requests made to the server. You need to correct the call made to server.js
route(handle,pathname,request,response);
This should solve it for you. I hope this helped. Let me know if there is anything else I can explain.
Been working on a Node.js restful web service that is hosted on OpenShift. Currently I have had success with simple method calls and such, but can not seem to get the http response to work through an asynchronous callback.
Here is what I currently have:
var http = require("http");
var url = require("url"); // used to get the requested method name as well as parameters
var util = require("util");
// global variables
// router function
function route(pathname, query, callbackFunc) {
//return executeMethod(pathname, query);
var returnValue;
switch (pathname.toUpperCase()) {
case "/ADD":
returnValue = add(query['num1'], query['num2']);
//util.process.nextTick(function() {
//callbackFunc(null, returnValue);
//});
break;
case "/ADDASYNC":
//addAsync(query['num1'], query['num2'], callback);
break;
default:
returnValue = "method not found";
break;
}
//return returnValue;
//return "Route for request " + pathname + " complete, query: " + query;
}
// actual web method execution
function add(num1, num2){
//return "add method called with values: " + num1 + " " + num2;
return parseFloat(num1) + parseFloat(num2);
}
function addAsync(num1, num2, callback){
//util.process.nextTick(function(){
// var value = parseFloat(num1) + parseFloat(num2);
// util.process.nextTick(function(){
// callback(value);
// });
//});
}
// main request handler for server
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
var query = url.parse(request.url, true).query;
console.log("Request for " + pathname + " Recieved");
response.setTimeout(500);
var myCallback = function(err, data){
if(err){
response.writeHead(200, {"Content-Type": "text/plain"});
response.write('an error occured with requested method');
response.end();
}else{
response.writeHead(200, {"Content-Type": "text/plain"});
response.write(data);
response.end();
}
}
//var finalValue = route(pathname, query);
//var finalValue = 0;
(function(){route(pathname, query, myCallback)})();
response.writeContinue();
//process.nextTick(myCallback(null, 'hello world'));
setTimeout(function(){
myCallback(null, "hello world");
}, 15);
//myCallback();
//response.writeHead(200, {"Content-Type": "text/plain"});
//response.write("Hello World. You requested: " + pathname + " with type " + pathname.type + ", value: " + finalValue);
//response.end();
}
// create the server and signal console of start
http.createServer(onRequest).listen(8080, process.env.OPENSHIFT_INTERNAL_IP);
// for debug
//http.createServer(onRequest).listen(process.env.PORT, process.env.IP);
console.log("Server has started. Listening to port: " + 8080 + " ip address: " + process.env.OPENSHIFT_INTERNAL_IP);
If I call the myCallback method directly inside the onRequest method, then I get a response back without any issues; however, calling the myCallback function inside the onRequest or route methods using process.nextTick or setTimeout does not seem to be working. I am working on this project using the Cloud9 IDE with direct git push to OpenShift so I am having some difficulties with my debug but have tried quite a few different approaches with no success, including setting the request.setTimeout function to provide some time for the timer/process event to fire. My current OpenShift app is running Node.js 0.6. Is there anything Obvious that could be causing issues that I might be missing?
I got your setTimeout to work by doing this:
comment out "response.setTimeout(500);" on line 54. It's invalid.
comment out "(function(){route(pathname, query, myCallback)})();" on line 71. Also invalid.
change timeout time to 5000 on line 76 (5000ms = 5 seconds)
For nextTick to work:
everywhere only do "process.nextTick" not "util.process.nextTick".
change line 16 to: "returnValue = add(query['num1'], query['num2']).toString();" (have to cast it as a string!)
uncomment 17, 18, 19 to see this will now work
comment out line 54, you don't need this
change line 70 to "route(pathname, query, myCallback);"
You should see what you did wrong now.
I'm a long time PHP (CodeIgniter & WordPress) developer that only recently wanted to learn a few other languages. I've set out to learn Ruby (on Rails, and Sinatra), Python (w/ Flask framework) and Javascript with node.js.
I decided to create the most basic application I can think of, a URL expander, using each of these languages. I have managed to create a working version in every language, except node.js and Javascript.
I kinda know my problem, I know it is related to callbacks. I know I'm not doing it right. I get the basic idea of callbacks, but I just cannot figure out how to fix this mess I have created.
This is my whole code:
var http = require('http');
var url = require('url');
function expand() {
var short = url.parse('http://t.co/wbDrgquZ');
var options = {
host: short.hostname,
port: 80,
path: short.pathname
};
function longURL(response) {
console.log(response.headers.location);
}
http.get(options, longURL);
}
function start() {
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {
"Content-Type": "text/plain"
});
response.write("Hello World");
expand();
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
start();
The server starts, and when a request is made, it calls the expand function which returns the expanded URL in the terminal. I'm trying to get it to print in the browser.
Any help is appreciated. Thanks in advance.
You've made a few flaws.
You should rewrite expand to pass the url in and pass a callback in. Any function that does anything asynchronous generally has the signature (data, callback) in node. This basically allows you to say I want this function to do something then tell me when it's done.
function expand(urlToParse, callback) {
// note we pass in the url this time
var short = url.parse(urlToParse);
var options = {
host: short.hostname,
port: 80,
path: short.pathname
};
// note we store the clientRequest object temporarily
var clientRequest = http.get(options, extractRealURL);
// Always attach the error handler and forward any errors
clientRequest.on("error", forwardError);
function extractRealURL(res) {
callback(null, res.headers.location);
}
function forwardError(error) {
callback(err);
}
}
Here the callback is expected to have the signature of (err, data) which almost all callbacks in node have. We've also added error handling which is a must.
We now change onRequest to actually call expand properly
function onRequest(request, response) {
// parse the incoming url. true flag unpacks the query string
var parsedUrl = url.parse(request.url, true),
// extract the querystring url.
// http://localhost:8888/?url=http://t.co/wbDrgquZ
urlToExpand = parsedUrl.query.url;
// call expand with the url and a callback
expand(urlToExpand, writeResponse);
function writeResponse(error, newUrl) {
// handle the error case properly
if (error) {
response.writeHead(500, { 'Content-Type': 'text/plain'});
// early return to avoid an else block
return response.end(error.message);
}
response.writeHead(200, { 'Content-Type': 'text/plain'});
// write the new url to the response
response.end(newUrl);
}
}
Here we have added error handling logic and also unpacked the actual url to expand from the query string.
Generally the pattern of doSomething<data, callback<err, result>> works very well in node.js.
It's the exact same as let result = doSomething<data> mayThrow err that you expect in your normal blocking languages except it's asynchronous.
Note that the alternative option of passing the ServerResponse object into the function is frowned upon, by doing so your creating unnecessary hard coupling between the expand function and the server response.
The expand function should only expand an url and return the expanded url, it has no business doing IO itself.
Full code
A callback is just a word to describe a function that we pass to some other code for that other code to invoke.
In your example, onRequest is a callback function that gets passed to createServer to be invoked whenever a request is received.
I think the issue you're having is that you're expecting expand() to have access to all the same variables/parameters that the onRequest function has access to. This isn't the case.
You need pass the response object to expand(). Because the call to expand creates a new callback longURL for the http.get call, it will have access to the response object that you passed in.
function expand( resp ) {
// receive the original response object, and end the response when ready
var short = url.parse('http://t.co/wbDrgquZ');
var options = {
host: short.hostname,
port: 80,
path: short.pathname
};
function longURL( response ) {
console.log(response.headers.location);
resp.end( response.headers.location ); // end the original response
}
http.get(options, longURL);
}
function start() {
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {
"Content-Type": "text/plain"
});
response.write("Hello World");
expand( response ); // pass this response object to expand
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
You weren't sending the response as a parameter to the expand function and also you were calling response.end() before the expand() function could write anything, here's the corrected version:
var http = require('http');
var url = require('url');
function expand(res) {
var short = url.parse('http://t.co/wbDrgquZ');
var options = {
host: short.hostname,
port: 80,
path: short.pathname
};
function longURL(response){
console.log(response.headers.location);
res.end("<br />" + response.headers.location);
}
http.get(options, longURL);
}
function start() {
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("Hello World");
expand(response);
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
start();
I'm a newb to back-end code and I'm trying to create a function that will respond to me a JSON string. I currently have this from an example
function random(response) {
console.log("Request handler 'random was called.");
response.writeHead(200, {"Content-Type": "text/html"});
response.write("random numbers that should come in the form of json");
response.end();
}
This basically just prints the string "random numbers that should come in the form of JSON". What I want this to do is respond with a JSON string of whatever numbers. Do I need to put a different content-type? should this function pass that value to another one say on the client side?
Thanks for your help!
Using res.json with Express:
function random(response) {
console.log("response.json sets the appropriate header and performs JSON.stringify");
response.json({
anObject: { item1: "item1val", item2: "item2val" },
anArray: ["item1", "item2"],
another: "item"
});
}
Alternatively:
function random(response) {
console.log("Request handler random was called.");
response.writeHead(200, {"Content-Type": "application/json"});
var otherArray = ["item1", "item2"];
var otherObject = { item1: "item1val", item2: "item2val" };
var json = JSON.stringify({
anObject: otherObject,
anArray: otherArray,
another: "item"
});
response.end(json);
}
var objToJson = { };
objToJson.response = response;
response.write(JSON.stringify(objToJson));
If you alert(JSON.stringify(objToJson)) you will get {"response":"value"}
You have to use the JSON.stringify() function included with the V8 engine that node uses.
var objToJson = { ... };
response.write(JSON.stringify(objToJson));
Edit: As far as I know, IANA has officially registered a MIME type for JSON as application/json in RFC4627. It is also is listed in the Internet Media Type list here.
Per JamieL's answer to another post:
Since Express.js 3x the response object has a json() method which sets
all the headers correctly for you.
Example:
res.json({"foo": "bar"});
in express there may be application-scoped JSON formatters.
after looking at express\lib\response.js, I'm using this routine:
function writeJsonPToRes(app, req, res, obj) {
var replacer = app.get('json replacer');
var spaces = app.get('json spaces');
res.set('Content-Type', 'application/json');
var partOfResponse = JSON.stringify(obj, replacer, spaces)
.replace(/\u2028/g, '\\u2028')
.replace(/\u2029/g, '\\u2029');
var callback = req.query[app.get('jsonp callback name')];
if (callback) {
if (Array.isArray(callback)) callback = callback[0];
res.set('Content-Type', 'text/javascript');
var cb = callback.replace(/[^\[\]\w$.]/g, '');
partOfResponse = 'typeof ' + cb + ' === \'function\' && ' + cb + '(' + partOfResponse + ');\n';
}
res.write(partOfResponse);
}
const http = require('http');
const url = require('url');
http.createServer((req,res)=>{
const parseObj = url.parse(req.url,true);
const users = [{id:1,name:'soura'},{id:2,name:'soumya'}]
if(parseObj.pathname == '/user-details' && req.method == "GET") {
let Id = parseObj.query.id;
let user_details = {};
users.forEach((data,index)=>{
if(data.id == Id){
user_details = data;
}
})
res.writeHead(200,{'x-auth-token':'Auth Token'})
res.write(JSON.stringify(user_details)) // Json to String Convert
res.end();
}
}).listen(8000);
I have used the above code in my existing project.
The JSON.stringify() method converts a JavaScript object or value to a JSON string, optionally replacing values if a replacer function is specified or optionally including only the specified properties if a replacer array is specified.
response.write(JSON.stringify({ x: 5, y: 6 }));
know more