I am still a beginner in Node.js and I am trying to explore as much as I can.
I know that Express.js is a framework used by many people for creating websites in Node.js.
But without using Express.js, I know that it is it possible to read .html files using 'fs.readFile', and then "display" this .html file in the browser.
Is there a way to get user input (say a button click, or fill in a box) from this web page into Node.js? So far, I have not found any examples of this.
Yes, this is possible. Study how the connect bodyParser's urlencoded function works.
When a request comes in from the browser, node is going to represent this as a readable data stream. For web forms, the pattern will be:
Use the request's data and end events to buffer the chunks of data from the stream into a single string.
Parse that string appropriately given its data format. In the case of a web form, this will normally urlencoded (application/x-www-form-urlencoded) MIME type
.
var qs = require('qs'); //https://github.com/visionmedia/node-querystring
function handle(req, res) {
var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){
//assemble the request from distinct chunks into a single string
buf += chunk
});
req.on('end', function(){
//OK, you have a usable string request body, parse it and handle it
try {
var formData = qs.parse(buf);
//Yay, it parsed. Now you have your form data
//depending on your form's html, you might have formData.email, for example
} catch (err){
//oops, respond with an error
}
});
}
Tutorial
Long story short:
http.createServer(function (req, res) {
var data = '';
req.on('data', function(chunk) {
console.log("Received body data:");
console.log(chunk);
data += chunk.toString();
});
req.on('end', function() {
console.log('Received Data: ', data);
res.end();
});
}
Related
I'm trying to access the body parameters from the request using only the http internal module from NodeJS. I've looked up everywhere and I can't seem to find how to do that other than using express or some other library. I know that with express you do that by simply using req.body.myparameter. Can I do it only with http?
You will then need to handle data Buffer manually:
if (req.method === 'POST') {
let body = '';
req.on('data', chunk => { //start reading data
body += chunk.toString(); // convert Buffer to string
});
req.on('end', () => {
console.log(body); //logging submitted data
res.end('ok');
});
}
I am using express to interact with an IoT device. The device interacts correctly with a Django server I wrote, but not with the node.js server I'm writing now. It appears that device writes a first packet with the HTTP headers (including "Content-Length") and the final "\r\n\r\n", and then a second packet with the POST body. Express is calling my post handler with no body.
Like I said, Django handles this correctly. I THINK what is being done is legal HTTP/TCP and Express is not waiting for the full length of the "Content-Length" header when it should. Is this a part of Express' design? Can I turn it off so that it waits for the whole document? Is this a bug and I should use a different framework with this device?
The express framework is unique among http frameworks in that it gets smaller each release. One of the parts that was removed from the core is body parsing, so it now handles request bodies as base node.js does unless you add middleware.
In a standard post handler the request object is a stream containing the headers which allows you to react to the request before the request has even finished sending data.
It's easiest to see with an echo handler:
echo (req, res) {
req.pipe(res);
}
But most the time you want to process the post body as a whole
postBody (req, res) {
let body = '';
req.on('data', d => body += d.toString()); // it comes in as a buffer
req.on('error', e => { res.statusCode = 400; res.end('bad post data'); });
req.on('end', () => /*do something with the body */ res.end(body));
}
Which means the minimal middleware simply calls next after assigning the body to req.body. Though in practice you should use https://github.com/expressjs/body-parser or the like since it handles edge cases etc . . .
bodyMiddleware (req, res, next) {
let body = '';
req.on('data', d => body += d.toString()); // it comes in as a buffer
req.on('error', e => { res.statusCode = 400; res.end('bad post data'); });
req.on('end', () => { req.body = body; next(); });
}
I'm using Node.js and connect to create a simple web server. I have something similar to the following code and I can't figure out how to access the actual request message body from the request object. I'm new to this so bear with me. I'm also taking out some of the stuff that's not necessary for the example.
function startServer(dir) {
var port = 8888,
svr = connect().use(connect.static(dir, {"maxAge" : 86400000}))
.use(connect.directory(dir))
/*
* Here, I call a custom function for when
* connect.static can't find the file.
*/
.use(custom);
http.createServer(svr).listen(port);
}
function custom(req, res) {
var message = /* the message body in the req object */;
// Do some stuff with message...
}
startServer('dirName');
Make sense? I've tried logging that object to the console and it is full of TONS of stuff. I can easily see headers in there plus the request URL and method. I just can't seem to isolate the actual message body.
You should include the connect.bodyParser middleware as well:
svr = connect().use(connect.static(dir, {"maxAge" : 86400000}))
.use(connect.directory(dir))
.use(connect.bodyParser())
.use(custom);
That will provide the parsed message body as req.body to your handler.
If you want the raw message body, you shouldn't use it but instead read the req stream yourself:
function custom(req, res) {
var chunks = [];
req.on('data', function(chunk) {
chunks.push(chunk);
});
req.on('end', function() {
var rawbody = Buffer.concat(chunks);
...do stuff...
// end the request properly
res.end();
});
}
if(req.method == "POST"){
var body = '';
req.on('data', function(data){
body += data;
});
}
Then body should contain your message if you posted correctly.
A better idea would be to use Express, then use the bodyparser middleware - which will give you this functionality out of the box without worrying about somebody hammering your server. The code above has NO functionality to worry about attacks - but it will get you started.
I have a node service that fetches a pdf from an API and serves that pdf.
When I curl or directly open the API, I do see the correct pdf.
But when I serve it from my Node app, I get an empty pdf.
Here's the section of my code that does the pdf render.
} else if (options.type === 'pdf') {
res.writeHead(200, {'content-type' : 'application/pdf', 'content-disposition': 'attachment; filename=invoice.pdf'});
res.end(data.invoice);
I've console.log'ed data.invoice to know it's the right stuff.
typeof(data.invoice) gives string; but I've also tried res.end(new Buffer(data.invoice)); which didn't work either.
Here's the section of my code that fetches the data
var http_options = {
method : options.method
, host : Config.API.host
, path : options.path
, port : Config.API.port
, headers : options.headers
};
var req = http.request(http_options, function (response) {
var raw_response = "";
response.on('data', function (response_data) {
raw_response += response_data.toString();
});
response.on('end', function () {
if (response.statusCode !== 200) {
cb(raw_response);
} else {
cb(false, raw_response);
}
});
});
req.setTimeout(timeout, function () {
req.abort();
cb("API connection timed out");
});
req.on('error', function (error) {
cb("API error while requesting for " + options.path + '\n' + error + '\n' + "http options: " + JSON.stringify(http_options)
});
req.end();
It's quite likely that the toString() and concatenation when you're receiving the PDF are corrupting it. Try writing raw_response to a file (you can use writeFileSync() since this is just a one-time test) and doing a byte-for-byte comparison with the same PDF retrieved with curl.
Note that if the process of string conversion has corrupted it, trying to convert it back to a buffer before sending it won't help. You'll have to keep the whole thing as a buffer from start to finish.
Since you don't intend to modify or read this data in transit, I suggest just using the pipe function to pipe all the data coming in from response out to req. this question has a good sample, but here's an excerpt.
req.on('response', function (proxy_response) {
proxy_response.pipe(response);
response.writeHead(proxy_response.statusCode, proxy_response.headers);
});
Note that there's no reason to convert the chunks coming in from the response from Buffers to something else, just write them through as unmodified buffers, and stream them (this is what pipe will do for you) instead of accumulating them to get maximum efficiency (and node.js streaming hipster points).
I'm trying to download a favicon from a website using Node.js, but am having some trouble.
My code is as follows:
//Imports ...
var theurl = http.createClient(80, 'a1.twimg.com');
var requestUrl = 'http://a1.twimg.com/a/1284159889/images/favicon.ico';
var request = theurl.request('GET', requestUrl, {"host": "a1.twimg.com"});
request.end();
request.addListener('response', function (response)
{
var body = '';
response.addListener('data', function (chunk) {
body += chunk;
});
response.addListener("end", function() {
fs.writeFileSync('favicon.ico', body.toString('binary'), 'binary');
});
});
The resulting icon is just garbage, however, and I suspect it has something to do with the encoding of the favicon when I grab it this way. What's the correct way to do something like this?
Try as a first line in the response callback response.setEncoding('binary'), or (since that's not a preferred (by node) encoding to set) response.setEncoding(null), which will make it a Buffer. And then just write body directly, without performing anything on it.
fs.writeFileSync('favicon.ico', body, 'binary');
I had to do response.setEncoding("binary") and provide the third argument to writeFileSync:
fs.writeFileSync('favicon.ico', body, 'binary')
This combination worked for me. Thanks.