function delete(id, response) {
var https = require('https');
var linkpath = "/v1/endpoint/" + id + "/?token=" + AUTH_KEY;
var req = https.request({
hostname: 'api.foo.com',
port: 443,
path: linkpath,
agent: false,
method: 'DELETE',
}, (res) => {
if (res.statusCode !== 200) {
response.send('HTTP ' + res.statusCode + ' ' + res.statusMessage);
}
res.on('error', function (err) {
response.send(err);
});
res.on('end', function (data) {
response.send(data);
});
});
req.on('error', function(e) {
response.send(e.message);
});
req.end();
}
This code, adapted from my (working) code that uses a POST request to do other things with this API, nets me a status code of 500 from the endpoint.
I don't know how to debug this. I can't send the URL manually to the server because it's a DELETE operation instead of a GET or POST.
Has anyone seen this problem? Or do you have ideas on how to debug it?
Postman (https://www.getpostman.com/) is a great tool for manually sending specific HTTP requests, including DELETE!
There are all sorts of tools that will let you manually send any HTTP to the server. For instance, you can get quite a bit of information with curl, which will happily send a DELETE request.
For example:
curl -v -X "DELETE" https://jsonplaceholder.typicode.com/posts/1
will return the request and response headers as well as the body of the return value if any.
Related
Intro:
I have and angular frontend and node backend (Server A) working fine. Using nginx as well for Server A.
Now from my node server (Server A) I need to call an API endpoint of other server (Server B).
Nginx configurations for Server B wont matter because curl command is working fine.
I have a PUT and POST https outgoing request from my node server to other server. On my system I have nginx service working.
The API is working fine when I use curl from the terminal but for the same thing via node https module the server is giving 400 BAD REQUEST.
What is the process for outgoing requests for nginx?
Why is the curl command working and node env requests not working?
curl -i --insecure --request PUT --url https://example.com:443/update --header 'content-type:application/json' --data '{"example":"Goodmorning"}'
httpsRequest(serverurl, method, header, data, callback){
console.log("httpsRequest function body")
let datastr = "";
if (data !== undefined)
datastr = JSON.stringify(data);
const options = {
host:'example.com',
port : 443,
rejectUnauthorized: false,
path : "/update",
body : datastr,
method : method,
secure:false,
key : readFileSync("example.key"),
cert : readFileSync("example.crt"),
};
if (header !== undefined) {
options['headers'] = header
};
}
console.log("options\n", options);
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
options.agent = new https.Agent(options);
// options.agent = httpsAgent;
const req = https.request(options, (res) => {
console.log('status code ', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
console.log(d);
if(res.statusCode === "errorexample"){
callback(null, {data : "success"})
}else{
let errormsg = {
message : res.message,
statusCode : res.statusCode,
failureAlarmCode : res.failureAlarmCode
}
callback(null, { "error": errormsg });
}
});
});
req.on('error', (e) => {
console.error(e);
callback(e, null);
});
req.end();
}
I think the curl from terminal does not route via the client nginx, hence some difference there. AM I correct?
I see a couple problems in the code in your question:
There appears to be some mismatched bracing that closes your function before you want it closed.
You aren't sending the body of the request. https.request() does not have a body option. Instead, you use req.write(datastr) to send the body. You can see in the doc that there is no body property in the options object and it also shows a code example where req.write() goes. Since a POST request is required to have a body, this could be the cause of your error.
You are creating a new https agent, but not passing it appropriate arguments. It's unclear why you are creating a new agent as that would not generally be required and if you are going to do that, you'd have to specify the reason and then use appropriate arguments. In my code solution below, I've removed the code creating a new agent since it isn't correct. In its place, I added agent: false to the option object which will create a new agent specifically for this request with default options. If you want to customize the options, then you need to create an agent using the proper options shown in the doc.
You are including key and cert in a client request. This is not typically required for a client request unless the server specifically requires client certificate authentication. But, your curl request does not supply these so apparently they are not needed. I'd suggest removing those two options.
Here's your code with these issues changed:
httpsRequest(serverurl, method, header, data, callback) {
console.log("httpsRequest function body")
let datastr = "";
if (data !== undefined)
datastr = JSON.stringify(data);
const options = {
host: 'example.com',
port: 443,
rejectUnauthorized: false,
path: "/update",
method: method,
secure: false,
// create new agent with default values just for this request
agent: false,
};
if (header !== undefined) {
options['headers'] = header
}
console.log("options\n", options);
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
const req = https.request(options, (res) => {
console.log('status code ', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
process.stdout.write(d);
console.log(d);
if (res.statusCode === "errorexample") {
callback(null, { data: "success" })
} else {
let errormsg = {
message: res.message,
statusCode: res.statusCode,
failureAlarmCode: res.failureAlarmCode
}
callback(null, { "error": errormsg });
}
});
});
req.on('error', (e) => {
console.error(e);
callback(e, null);
});
req.write(datastr);
req.end();
}
You may also want to note that res.on('data', ...) can receive more than one data event so you could be calling your callback more than once.
One other thing that look suspicious here is your inclusion of these two options:
key: readFileSync("example.key"),
cert: readFileSync("example.crt"),
This is a client request. You would not normally need to supply these unless the target server requires client certificate authentication which it does not appear to because your curl command does not provide these. I would suggest removing these from your options object.
I have been trying this out for a long time now.
I want to scrap contents from a subreddit that has adult contents.
But, the problem is that, you have to answer a simple question before you are given access to that page i.e. if you are 18+ or not.
I did some research on the source code and found that the solution is a simple POST request. where you need to send the parameters "over18=yes".
But my problem is that, I am not able to access the response body after the post.
Here's the code using http request in node. I have even tried it out with the node "request" module, but no help from that either.
Hoping to find someone who can help me out here.
var http = require("http");
var options = {
host: 'www.reddit.com',
port: 80,
path: '/over18?dest=http%3A%2F%2Fwww.reddit.com%2Fr%2Fnsfw&over18=yes',
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();
And here is the code using the Node Request module
var request = require("request");
request.post({url:'http://www.reddit.com/over18?dest=http%3A%2F%2Fwww.reddit.com%2Fr%2Fnsfw', form: {over18:'yes'}}, function(err,httpResponse,body){
console.log(body);
});
the URL i am trying to access is http://www.reddit.com/r/nsfw
In short, when you click YES button, the form sends over18=yes parameter to url http://www.reddit.com/over18?dest=http%3A%2F%2Fwww.reddit.com%2Fr%2Fnsfw using POST method. Then, server responds with an 302 Redirection header, cookie with value over18=1 and finally redirects to url http://www.reddit.com/r/nsfw using GET request. THen, server just checks if youa have a cookie with needed valuse.
All what you need is to do request directly to the final url with cookies using GET method.
var request = require("request");
var target = "http://www.reddit.com/r/nsfw";
var jar = request.jar();
var cookie = request.cookie("over18=1");
cookie.domain = "reddit.com";
cookie.path = "/";
jar.setCookie(cookie, target, function(error, cookie) {
console.log(error);
console.log(cookie);
});
request({
uri: target,
method: "GET",
jar: jar
}, function(error, response, body) {
console.log(response.statusCode);
console.log(body);
});
I too ran into this while ahem doing some research.. Here's my version:
var url = 'http://www.reddit.com/r/nsfw/';
var request = require('request');
request = request.defaults({jar: true });
request.post({
followAllRedirects: true,
url: 'http://www.reddit.com/over18?dest=' + encodeURIComponent(url),
form: {uh: '', over18: 'yes', }
}, function(err, httpResponse, html) {
…
});
Also worth a try are Reddit's Node.js APIs, of which I personally liked Snoocore.
I have an application based on NodeJS/Express and AngularJS which talks to a, application server via REST API. In the event that the application server is not running, I would like to immediately return an error to the AngularJS client that the calls are failing.
Here is what I currently have:
var jsonObject = JSON.stringify(input);
var postHeaders = {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(jsonObject, 'utf8')
};
var options = {
host: '127.0.0.1',
port: 7777,
path: path,
method: method,
headers: postHeaders
};
var appServerRequest = http.request(options, function(appServerResult) {
console.log('STATUS: ' + appServerResult.statusCode);
console.log('HEADERS: ' + JSON.stringify(appServerResult.headers));
appServerResult.setEncoding('utf8');
var responseDataString = '';
appServerResult.on('data', function(chunk) {
responseDataString += chunk;
console.log('BODY: ' + chunk);
});
appServerResult.on('end', function() {
callback(responseDataString);
});
appServerResult.on('error', function(e) {
console.log('** Result ERROR in appServerResponse');
console.log(e);
});
});
appServerRequest.on('response', function(response) {
console.log('Response: ' + response);
});
appServerRequest.on('error', function(e) {
console.log('** Request ERROR in appServerRequest');
console.log(e);
});
appServerRequest.write(jsonObject);
appServerRequest.end();
As you can see, I'm listening to the 'error' events on both the Request and Response objects. When a call is made and the application server is not running, the Request error handler is called as expected. However, I haven't been able to figure out how to take that error and return it to the client. A response object is eventually returned, but only after the timeout expires. It seems like there should be a way to return a Response and specify an appropriate HTTP Status code as soon as I detect the error. I could do it if I had a response object (of course), but I don't get one until the timeout expires.
I know I must be missing something simple, but I can't figure out what it is.
You mention you're using express. Simply call res.send(500) to end the request with an error code (in this case 500)
How can we stop the remaining response from a server -
For eg.
http.get(requestOptions, function(response){
//Log the file size;
console.log('File Size:', response.headers['content-length']);
// Some code to download the remaining part of the response?
}).on('error', onError);
I just want to log the file size and not waste my bandwidth in downloading the remaining file. Does nodejs automatically handles this or do I have to write some special code for it?
If you just want fetch the size of the file, it is best to use HTTP HEAD, which returns only the response headers from the server without the body.
You can make a HEAD request in Node.js like this:
var http = require("http"),
// make the request over HTTP HEAD
// which will only return the headers
requestOpts = {
host: "www.google.com",
port: 80,
path: "/images/srpr/logo4w.png",
method: "HEAD"
};
var request = http.request(requestOpts, function (response) {
console.log("Response headers:", response.headers);
console.log("File size:", response.headers["content-length"]);
});
request.on("error", function (err) {
console.log(err);
});
// send the request
request.end();
EDIT:
I realized that I didn't really answer your question, which is essentially "How do I terminate a request early in Node.js?". You can terminate any request in the middle of processing by calling response.destroy():
var request = http.get("http://www.google.com/images/srpr/logo4w.png", function (response) {
console.log("Response headers:", response.headers);
// terminate request early by calling destroy()
// this should only fire the data event only once before terminating
response.destroy();
response.on("data", function (chunk) {
console.log("received data chunk:", chunk);
});
});
You can test this by commenting out the the destroy() call and observing that in a full request two chunks are returned. Like mentioned elsewhere, however, it is more efficient to simply use HTTP HEAD.
You need to perform a HEAD request instead of a get
Taken from this answer
var http = require('http');
var options = {
method: 'HEAD',
host: 'stackoverflow.com',
port: 80,
path: '/'
};
var req = http.request(options, function(res) {
console.log(JSON.stringify(res.headers));
var fileSize = res.headers['content-length']
console.log(fileSize)
}
);
req.end();
I've tried the sample from the documentation and it works great.
But when I change the URL to https://api.mercadolibre.com/sites/, the request hangs. The only thing I get is:
{ [Error: socket hang up] code: 'ECONNRESET' }
Here's my code:
var https = require('https');
this.dispatch = function(req, res) {
var renderHtml = function(content) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(content, 'utf-8');
}
var parts = req.url.split('/');
var options = {
host: 'api.mercadolibre.com',
port: 443,
path: '/sites/',
method: 'GET'
};
var request = https.request(options, function(res) {
console.log("statusCode: ", res.statusCode);
console.log("headers: ", res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
});
request.on('error', function(e) {
console.error('error');
console.error(e);
});
request.end();
return 'item id:' + parts[2];
};
I've tried with curl, soapui and with a browser. On all cases works great, but with node.js it doesn't.
How can I get more data on what's going on?
added
With curl i do: curl --sslv3 https://api.mercadolibre.com/sites/ works.
I've test same in centos 6 and works too.
I've reinstalled node, this time from source, same problem. My Os is ubuntu 12.04.
Thanks.
I'm not sure about api.mercadolibre.com site, but I can call API if I remove port param, like following code:
var options = {
host: 'api.mercadolibre.com',
path: '/sites/',
method: 'GET'
};
And we also need add param to support SSL version 3:
https.globalAgent.options.secureProtocol = 'SSLv3_method';
Why not use a library like request to deal with the details for you?
var request = require('request');
request('https://api.mercadolibre.com/sites/', {}, function(err, res, body) {
console.log("Got body: ", body);
});
This yields:
Got body: [{"id":"MLA","name":"Argentina"},{"id":"MLB","name":"Brasil"},{"id":"MCO","name":"Colombia"},{"id":"MCR","name":"Costa Rica"},{"id":"MEC","name":"Ecuador"},{"id":"MLC","name":"Chile"},{"id":"MLM","name":"Mexico"},{"id":"MLU","name":"Uruguay"},{"id":"MLV","name":"Venezuela"},{"id":"MPA","name":"Panamá"},{"id":"MPE","name":"Perú"},{"id":"MPT","name":"Portugal"},{"id":"MRD","name":"Dominicana"}]
Since it is working with curl, try using node-curl module. I lost a whole day trying to make it work in node.js with http and/or https modules until I switched to node-curl.
Try this:
var curl = require('node-curl');
curl('https://api.mercadolibre.com/sites/', {SSLVERSION: 3}, function(err, res) {
var body = res.body;
res.close();
console.log(body);
});
Same here, working with curl but not with node.js.
Problem: here on CentOS-5 curl usesthe provides openssl libraries and so uses centos standard /etc/pki/tls/certs/ca-bundle.crt for CA checks.
Where does node.js look for?, via strace there I cannot see any reference to a CA-file for checking.
Node.js request against server with valid SSL-certificate from well known old issuer are accepted, but not against my own webserver with own CA.
I put my own CA.crt in the ca-bundle.crt file, so now curl accepts it, but not node.js.
Only solution for now is to deactivate the verification-check for my dev-box:
var client = require('https');
var download_options = url.parse(sourceUrl);
download_options.method = "GET";
download_options.agent = false;
download_options.rejectUnauthorized = false; / HERE to accept all SSL-certificates */
var download_request = client.request(download_options);
I think you are behind a proxy which you need to specify to request. Proxy settings are detected automatically by libcurl, which node-curl uses. Therefore the request passes in node-curl.
Therefore, find out the proxy IP and port your organization uses, and try this:
var request = require('request');
request({
uri : 'https://mail.google.com/mail',
proxy : 'http://<proxy ip>:<proxy port>'
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body) // Print the google web page.
}else{
console.log(error);
console.log(response.statusCode);
}
})
You will get the ECONNRESET error if you do this:
post_options.path = 'history';
...
var req = http.request(post_options, function(res) {
...
That is, you need to make sure your path has a / like this:
post_options.path = '/history';
...