NOOb here. I've got a HTTP request that pulls all of the content from a specific webpage. However, all I need is a specific string:"Most recent instantaneous value: ". In fact, I actually need to store the value that follows value:. Here is my code:
var http = require("http");
var options = {
host: 'waterdata.usgs.gov',
port: 80,
path: '/ga/nwis/uv?cb_72036=on&cb_00062=on&format=gif_default&period=1&site_no=02334400',
method: 'POST'
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
I realize I don't need all the console.log statements, but do I need keep console.log('BODY: ' + chunk); so all of the data downloads?
Never do it the way I'm doing it in this quick'n'dirty example. There are plenty of modules for DOM traversal, HTML/XML parsing, etc... They are a lot safer then a simple regex. But just so you get the general idea:
var http = require("http");
var options = {
host: 'waterdata.usgs.gov',
port: 80,
path: '/ga/nwis/uv?cb_72036=on&cb_00062=on&format=gif_default&period=1&site_no=02334400',
};
function extract (body, cb) {
if(!body)
return;
var matches=body.match(/Most recent instantaneous value: ([^ ]+) /);
if(matches)
cb(matches[1]);
}
http.get(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
extract(chunk, function(v){ console.log(v); });
});
}).on('error', function(e) {
console.log('problem with request: ' + e.message);
});
Somehow I also got a different page when sending a POST instead of a GET request. So I changed that bit...
Regarding your second question: No you don't need to keep any of the console.log() statements. Just use callbacks and everything is fine! :-)
Related
I'm learning how to process credit card payments.. Here is the test CURL...
curl -k -v -X POST -H "Content-Type:application/json" -H "Authorization: Basic Mxxxxxxxxxxxxxxxxxx=" -d "#json_file.txt" -o output.txt https://w1.xxxxxxxxxxxx.net/PaymentsAPI/Credit/Sale
Where json_file.txt contains
{
"InvoiceNo":"1",
"RefNo":"1",
"Memo":"TEST_TEST_PHONY",
"Purchase":"1.00",
"AccountSource":"Swiped",
"AcctNo":"5xxxxxxxxxxxxxxxxx1",
"ExpDate":"0816",
"OperatorID":"xxxxxxxxxx",
}
I converted over to node module HTTPS
var https = require("https");
var options = {
host: 'w1.xxxxxxxxxxxxxx.net',
port: 443,
path: '/PaymentsAPI/Credit/Sale',
headers: { "Content-Type" :"application/json",
"Authorization" : "Basic Mxxxxxxxxxxxxxxxxxxxxxxxxxxx="} ,
data: {
"InvoiceNo":"1",
"RefNo":"1",
"Memo":"xxxxxxxxxxxxxxx",
"Purchase":"1.00",
"AccountSource":"Swiped",
"AcctNo":"5xxxxxxxxxxxxxxxxx1",
"ExpDate":"0816",
"OperatorID":"xxxxxxxxxxxx",
},
method: 'POST'
};
// oops... 400 Bad Request
// The request could not be understood by the server due to malformed syntax.
var req = https.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk.toString() );
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
Problem is on the original curl request, the data contained within the JSON text file is submitted as a POST attachment. Curl request works fine. On the other hand its not clear to me on how to do that from a node.js server. The response headers come back fine, but I get a 400 response (malformed syntax). Anybody know how to attach JSON data as a post attachment to a HTTPS request?
Oops. I totally didn't understand how the req.write() stuff works.. This code is successful. Thanks to Dan Ourada # Mercury Payments for his assistance. Note, all code here is pure sandbox. No real $$ going buy buy.
var https = require("https");
var options = {
host: 'w1.mercurycert.net',
port: '443',
path: '/PaymentsAPI/Credit/Sale',
headers: { "Content-Type" :"application/json", "Authorization" : "Basic MDAzNTAzOTAyOTEzMTA1Onh5eg=="},
method: 'POST'
};
var inputdata = JSON.stringify( {
"InvoiceNo":"1",
"RefNo":"1",
"Memo":"XXXXX",
"Purchase":"1.00",
"AccountSource":"Swiped",
"AcctNo":"5499990123456781",
"ExpDate":"0816",
"OperatorID":"money2020",
} );
var req = https.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Return info: ' + chunk); // output the return raw data
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// attach input data to request body
req.write(inputdata);
req.end();
Info offered here in case anybody else gets stuck converting from a CURL command over to a Node.js http request...
And hey, after playing around with this, I'm amazed on how truly easy it is to incorporate a real (and secure) payments system into any merchant website. (Obviously Https site required.)
The script that I am using is:
var http = require('http');
var options = {
host: 'some url',
port: 80,
path: 'path',
method: 'POST'
};
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
req.write('username=abcd&password=defg');
req.end();
I am getting a response as 404 bad request by server.. but when I use the firefox add-on "poster" for posting the same parameters to the server.. I am getting a proper reply, i.e 200 status code.. I think this the problem with the string I am passing in req.write(). but the same string is working fine with poster.. Can someone explain what the issue is?
It looks to me that a Content-Type header is missing. It probably should be set to application/x-www-form-urlencoded
This is my little piece of code:
var options = {
host: 'www.cuantocabron.com',
port: 80,
path: '/index.php',
method: 'GET'
};
var http = require('http');
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
});
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
I'm trying to get all the HTML code from that URL; the firts time that I run that code, the console prints all the HTML, but after that, throw an error, so my server goes down.
But, when I run it, the console throw an Error:
events.js:71
throw arguments[i]; //Unhandled 'error' event
Error: Parse Error
at Socket.socketOnData (http.js:1447:20)
at TCP.onread (net.js:404:27)
Any solution?
Thanks;
If you are only trying to get the HTML from that URL, you do not need the req.write statements. Those are the statements that are causing your error. You use req.write when you are writing data to the server, E.G. If you were doing a POST.
You should also add an on error handler after you declare your req
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
I am playing around vows and nodejs.
var vows = require('vows');
var http = require('http');
var suite = vows.describe('testing');
var host = 'www.google.com', port = '80', path = '/', method = 'GET';
suite.addBatch({
'A context': {
topic: function(){
http.get({
host: host,
port: port,
path: path,
method: method
}, this.callback);
},
"sample test": function(res, extra){//here extra is just to prevent vows error
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);//It never gets logged
});
console.log('HEADERS: ' + JSON.stringify(res.headers));//it is working
}
}
});
suite.export(module);
But I am unable to get the response body. What am I doing wrong.
I am using nodejs v 0.6.6 and vows v0.6.2
From what I can see, it looks like Vows doesn't directly invoke the test when this.callback runs. It is delayed by processnextTick. If I had to guess, maybe the 'data' event is being emitted during that time. That means you don't bind your 'data' function until after all the data events have been triggered.
Really though, the issue is that Vows tests are supposed to separate all async logic like this into the topic itself. If you really want to check the chunks in a test, then do it like this.
Also note that you can have any number of chunks, there isn't just a single data event. You may want to set the stream encoding, and join the data as strings. Your current code implicitly converts a Buffer to string, which can break for multi-byte characters.
suite.addBatch({
'A context': {
topic: function(){
var cb = this.callback;
var req = http.get({
host: host,
port: port,
path: path,
method: method
});
// Aggregate all chunks before running callback
req.on('response', function(res) {
var chunks = []
res.on('data', function(chunk) {
chunks.push(chunk);
});
res.on('end', function() {
cb(null, res, chunks);
});
});
// Handle connection failures.
req.on('error', cb);
},
"sample test": function(err, res, chunks){
chunks.forEach(function (chunk, i) {
console.log('BODY piece ' + i + ': ' + chunk);
});
console.log('HEADERS: ' + JSON.stringify(res.headers));
}
}
});
I've been trying to connect node to a web page and return the result in the same program. Here's the code I have:
var http = require('http'),
sys = require('sys'),
fs = require('fs');
var options = {
host: 'myurl.com',
port: 80,
path: '/path/to/file',
method: 'POST'
};
var myglobal = "the test";
var req = http.request(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
myglobal = chunk;
console.log("myglobal = " + myglobal);
});
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end();
console.log("outside of http request: myglobal = " + myglobal);
Now what I want to happen is for "myglobal" to have the contents of the output of the web page "myurl.com" at the end of the program. This doesn't happen however and I can't seem to figure out how to get the contents from the "chunk" into another variable in the program. I thought the contents would be in either the "req" or "res" variable but I dumped the vars and couldn't find the output in either place. So at the end, "myglobal" still says "the test", where the "myglobal" within the http.request code has the output of "chunk". Just curious to know what it is I'm missing here. Thanks.
Darryl
Not sure if I get you right. You want to work with the data (the body) you get via the POST request right? Then you have to continue working after all chunks have been received:
var http = require('http'),
sys = require('sys'),
fs = require('fs');
var options = {
host: 'blog.depold.com',
port: 80,
path: '/post/5936116582/changes-in-sequelize-1-0-0',
method: 'POST'
};
var req = http.request(options, function(res) {
var data = ""
res.setEncoding('utf8');
res.on('data', function (chunk) { data += chunk })
res.on('end', function() {
console.log("finished request", "data length:", data.length)
console.log("go on working here")
})
});
// write data to request body
req.write('data\n');
req.write('data\n');
req.end()
Been banging my head with this one for the past couple weeks and after trying a bunch of stuff decided to add "\0" at the end and it worked! So it seems that the socket.write automatically appends the "\0" outside of the "http.request" block, but doesn't append it within that block. So it would "queue" any http.request messages until I sent a message outside of that block, which would automatically be terminated by "\0". Why it works that way I have no idea, but there it is.