I have a problem with the following code that calls a remote service with a POST request and receives JSON data:
[..]
var options = {
host: REMOTE_HOST,
port: REMOTE_HOST_POST,
path: REMOTE_PATH,
method: 'POST'
};
var req = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (data) {
// handles OK
});
});
req.on('error', function(e) {
// handles KO
});
req.write('user=myname&password=mypassword');
req.end();
[..]
It works ok on my OSX machine, but when I try it on a co-worker Windows computer, the data sent to the server is wrong and I don't know what could be causing the problem. The remote application doesn't receive user=myname&password=mypassword as expected but:
35\r\nuser=myname&password=mypassword
What could be the cause of this? thanks
EDIT
Seems like the problem is not Node.js Further investigation evidences that also my OSX box gives the same error when calling the dev server, while it works ok in production. Seems like a Rails problem. I'
Related
I have following code. It sends simple GET request to the target server.
However when there's no webserver listening on given IP address, node keeps hanging for around 2 minute+ - totally disrespecting timeout value - which should be few seconds.
I've launched tcpdump and i noticed that node keeps sending SYN packets constantly to target server during these 2 minutes.
Why is this happening on http library? I tested alternative library (node-request) and timeout is working correctly there. However for some reasons, i can't use it and need to stick to lower level libs.
http = require('http');
const options = {
hostname: '52.178.167.109',
port: 80,
path: '/upload',
method: 'GET',
timeout: 5000, //5s timeout
};
const req = http.request(options, (res) => {
console.log(`STATUS: ${res.statusCode}`);
req.end();
});
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
// Write data to request body
req.end();
root#abc:~# time node test.js
problem with request: connect ETIMEDOUT 52.178.167.109:80
real **2m15.474s** <-------
user 0m0.616s
sys 0m0.084s
The timeout property is only applicable to socket inactivity. You want to use request.setTimeout to set a read timeout. The github ticket https://github.com/nodejs/node/issues/12005 clarifies this.
In Express I have a route that makes an http call to Amazon S3 to see if a specific image exists or not (it's basically a proxy call to bypass my inability to make a cross-domain call directly to Amazon from the browser).
The problem is that it works successively for a while and then suddenly just stops and is only fixed by my restarting my express app.
Just in case (though I believe the code is totally generic) here's the code:
Router.get('/testS3Image',
function(request, response){
try{
var imagePath = request.param('imagePath');
var https = require('https');
var options = {
method:'GET',
host: 's3.amazonaws.com',
path: '/' + imagePath,
port: 443
};
console.log("MAKING S3 call with options " + JSON.stringify(options));
var req = https.request(options,
function(res) {
try{
if(!res || !res.headers || !res.headers["content-length"])
throw ("image not found on S3");
console.log("returned from S3 call with success");
response.json({success:true,headers:res.headers});
}catch(e){
console.log("returned from S3 call with failure");
response.json({success:false, error:e});
}
}
);
req.end();
}catch(e){
}
});
after the https.request() call is made, nothing happens. It simply goes dark. I'm new enough to Node to not know how I can follow along to see what's happening beneath the hood. We're running this in nginx.
Since it works perfectly for a long time and then suddenly breaks with no obvious rhyme or reason I am suspecting some sort of http call limitation, but I am unclear on what I can do differently.
You're not reading the response data from S3; I wonder if this is causing the issue.
I'm aware that there are several questions related to mine, but I didn't find any of them useful:
this one doesn't apply to my case, I'm actually getting the answer, it's the contents that I can't get.
on this one, on the other hand, the problem is a wrong handling of an asynchronous call, which is not my case
there, well, I really didn't fully understand this question
And so on...
Then, I think this is a legitimate question. I'm actually performing some encryption in my server (express routing in node) through a post request:
app.post('/encrypt', encrypt);
Encrypt is doing:
function encrypt(req,res) {
if(req.body.key && req.body.message) {
var encryptedMessage = Encrypter.encrypt(req.body.key,req.body.message);
return res.status(200).json({ message: encryptedMessage });
}
res.status(409).json({ message: 'the message could not be encrypted, no key found' });
}
}
So, I tested this via console.log, and it's working. When the server receives the request, the encrypted message is being generated.
At the same time, I'm testing my thing with mocha and I'm doing it like so:
describe('# Here is where the fun starts ', function () {
/**
* Start and stop the server
*/
before(function () {
server.listen(port);
});
after(function () {
server.close();
});
it('Requesting an encrypted message', function(done) {
var postData = querystring.stringify({
key : key,
message : message
});
var options = {
hostname: hostname,
port: port,
path: '/encrypt',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': postData.length
}
};
var req = http.request(options, function(res) {
res.statusCode.should.equal(200);
var encryptedMessage = res.message;
encryptedMessage.should.not.equal(message);
done();
});
req.on('error', function(e) {
//I'm aware should.fail doesn't work like this
should.fail('problem with request: ' + e.message);
});
req.write(postData);
req.end();
});
});
So, whenever I execute the tests, it fails with Uncaught TypeError: Cannot read property 'should' of undefined because res.message does not exist.
None of the res.on (data, end, events is working, so I suppose the data should be available from there. First I had this:
var req = http.request(options, function(res) {
res.statusCode.should.equal(200);
var encryptedMessage;
res.on('data', function (chunk) {
console.log('BODY: ' + chunk);
encryptedMessage = chunk.message;
});
encryptedMessage.should.not.equal(message);
done();
});
But res.on was never accessed (the console.log didn't show anything). I'm therefore a bit stuck here. I'm surely doing some basic stuff wrong, but I don't have a clue, and the many questions I found doesn't seem to apply to my case.
Weird enough, if I launch a test server and then I curl it
curl --data "key=secret&message=veryimportantstuffiabsolutellyneedtoprotect" localhost:2409/encrypt
Curl justs waits ad aeternam.
Actually I was doing it properly at the beginning, and the problem was indeed the same than in the second question I mentionned I was actually "clearing" my context with done() before the post data arrived. The solution is:
var req = http.request(options, function(res) {
res.statusCode.should.equal(200);
res.on('data', function(data) {
encryptedMessage = JSON.parse(data).message;
encryptedMessage.should.not.equal(message);
done();
});
});
In such a way that done() is only called when the data has been threated. Otherwise, mocha will not wait for the answer.
I am new to Node.js, learning with examples.
Here is what I am trying to do, I have a geoserver running to serve GeoJson, I want to call geoserver WFS url and get json data using node.js. Here is code, when I run it, I get :
getaddrinfo ENOENT
var http = require('http');
var options = {
host: "local:8080/geoserver/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=layername&outputFormat=JSON&cql_filter=id=1";
path: '/'
}
var request = http.request(options, function (res) {
var data = '';
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
console.log(data);
});
});
request.on('error', function (e) {
console.log(e.message);
});
request.end();
Please guide me in right direction. Thank you.
You need to pass in the correct options:
host - should only be the host name
path - should the path to the resource on the host (all the stuff you have after the host name
method - should be GET or POST (GET in your case).
var options = {
host: "local:8080";
path: '/geoserver/wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=layername&outputFormat=JSON&cql_filter=id=1',
method: 'GET'
}
I was also trying to get a GeoJSON via Node.js and took a different approach; I used Express and sequelizejs. This allowed me to get objects directly from Postgres / PostGIS. I needed to do a little formatting client-side to form a valid GeoJSON from the express response.
I am using node.js v. 0.4.8. When I create a HTTPS server, I never get the response.on('end', ...) event (but I do for a HTTP one). I read the issue reports on node's github page - https://github.com/joyent/node/issues/728, and apparently this is an issue that regressed into 0.4.8. response.on('close', ...) seems to have the same functionality, but I do not know enough about HTTP/HTTPS to judge. Can I use it as replacement for response.on('end', ...), and is this likely to cause any problems in future?
You can see a code sample below.
Thanks in advance!
var request = "JSON_request";
var https = require('https');
var options = {
host:"someHost.com",
path:"somePath",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(request)
}
};
var req = https.request(options, function(res){
var response = "";
res.setEncoding('utf8');
res.on('data', function(chunk){
console.log("INFO: "+chunk);
response += chunk;
});
// This never happens
res.on('end', function(){
console.log("End received!");
});
// But this does
res.on('close', function(){
console.log("Close received!");
});
});
req.on('error', function(error){
console.log("Error: "+error);
});
req.write(request);
req.end();
I believe this issue has been fixed as of commit de09168, and there hasn't been any action on this question for months BUT here is the answer:
On the comments for issue 728 Node.js creator Ryan Dahl says:
This isn't a bug. Responses are not guaranteed to have an 'end' event. Use 'close'.
Though later he says:
i take back what i said before. we should probably make this work.
Either way it seems close and end are pretty much interoperable in this use case. The relevent code in the node.js core tls.js:681 renforces that interpretation:
process.nextTick(function() {
self.encrypted.emit('end');
self.cleartext.emit('end');
self.encrypted.emit('close');
self.cleartext.emit('close');
});
Since node.js 0.8.12 finish event is emitted on HTTP responses' end function. I wrote all the details in a similar question.