In our project, we make a call to a REST web service with Node using HTTP request. We can see the result when we log it into the console. But we would like to store it or use it outside of the HTTP request. How can we achieve that?
var http = require('http');
var options = {
host: 'http:\\example.com',
port: 80,
path : '/site/status?tag=A7351&date=09JAN&name=LASTNAME',
method : 'GET'
};
var result;
http.request(options, function(res){
var body = '';
res.on('data', function (chunk) {
body += chunk;
});
res.on('end', function () {
result = JSON.parse(body);
console.log(result, "INSIDE"); //Shows the JSON result
});
}).end();
console.log(result, "OUTSIDE"); //Shows Undefined
The result is in this format:
{
error: 0,
statut: 'STATUTTTTT',
origine: 'PLACEEE',
destination: 'PARIS',
onwardDate: null
}
We need to be able to get the result outside of the HTTP call.
The issue is that you're making an asynchronous call, but not handling it correctly. Dialogflow's library requires that when you make an async call you return a Promise.
The easiest solution is for you to switch from using the request library to using the request-promise-native library and to return the Promise.
See other answers on Stack Overflow for examples and more information.
Related
I want to get the html of this page for parsing(click the link to understand what content i want to get).
750-bond list
Here's my code to request this page content
var https = require("https");
var fs = require("fs");
var options = {
hostname: "www.prizebond.net",
port: 443,
path: "/dlist.php?num=455",
method: "GET"
};
var response = "";
var req = https.request(options, function (res) {
res.setEncoding("UTF-8");
console.log(res.statusCode);
res.on("data", function (chunk) {
response += chunk;
});
res.on("end", function () {
fs.writeFile("750-bond.html", response, function (err) {
if (err) {
console.log(err.message);
}
console.log("File downloaded");
});
console.log("end");
});
});
req.end();
Now the problem is that in my 750-bont.html file, I am getting the weird the
result of "Checking your browser before accessing the prizebond.net" not the
original content. Here's the screenshot what I got when I open the 750-
bond.html file in browser.
What I am doing wrong? And how can I get the original content of this webpage?
You can't, unless you write something more sophisticated, but you probably shouldn't.
The purpose of Cloudflare-protection is to prevent what you are trying to realize unfortunately.
You could look into a possibility to access whatever you want to access by a public API or something that prizebond.net provides for example.
Calling the Riot-Api Im receiving incomplete JSON on a https GET-request.
After debugging, I realized that depending how much I wait (breakpoint) pre-executing the
https on'data' callback Im actually receiving the complete JSON object.
(Average API response time for me is 200-300ms)
let getOptions = function(url) {
return {
host: 'na.api.pvp.net',
port: 443,
path: `${url}?api_key=${apiKey}`,
method: 'GET'
};
}
exports.Call = function(url, callback) {
let response = {};
let req = https.request(getOptions(url), function(res) {
response.statusCode = res.statusCode;
res.on('data', function(data) {
response.json = JSON.parse(data);
callback(response);
});
});
req.on('error', function(err) {
response.err = err;
callback(response);
});
req.end();
};
Running the code without breakpoints or only breaking a short time I run either into error:
JSON.parse(data): Unexpected Token in JSON at position ...
or
JSON.parse(data): Unexptected end of JSON Input.
As I expect the 'data' callback to be executed only after the request is complete im confused about how to fix it (without artificially delaying it ofc.).
http.request returns a stream – its not a simple callback that contains the whole response.
You will have to buffer and concatenate everything if you want to parse the whole response.
I would strongly recomment to use a helper library like got or request
I have a NodeJS API. The logic in the API needs to make an http get request to google.com, capture the response from google.com, and then return the html response to the original API call. My problem is capturing the http response from google asynchronously and returning it to the original API call.
// Entry point to /api/specialday
module.exports = function(apiReq, apiRes, apiNext) {
var options = {
host: 'www.google.com'
};
callback = function(googleRes) {
var str = '';
// another chunk of data has been recieved, so append it to `str`
googleRes.on('data', function (chunk) {
str += chunk;
});
// capture the google response and relay it to the original api call.
googleRes.on('end', function () {
apiRes.send(str);
});
}
http.request(options, callback).end();
}
The error I get here is Uncaught TypeError: Cannot read property 'send' of undefined. I understand why I'm getting the error (because apiRes is out of scope), I just can't figure out how to do it right. Any help much appreciated!
The reason you are seeing the above error is because the original response object apiRes is gone by the time you have received the response from the google API.
As far as I can tell you will have to bind() the apiRes twice (untested):
callback = function(googleRes) {
var str = '';
// another chunk of data has been recieved, so append it to `str`
googleRes.on('data', function (chunk) {
str += chunk;
});
// capture the google response and relay it to the original api call.
googleRes.on('end', function () {
apiRes.send(str);
}.bind(apiRes));
}.bind(apiRes)
A more modern solution would be to use promises for this task https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
Promises, that's it! Thanks Michal. Below is a simplified version of my implementation.
// Entry point to /api/specialday
module.exports = function(apiReq, apiRes, apiNext) {
var p1 = new Promise(
// The resolver function is called with the ability to resolve or
// reject the promise
function(resolve, reject) {
var options = {
host: 'www.google.com'
};
callback = function(googleRes) {
var str = '';
// another chunk of data has been recieved, so append it to `str`
googleRes.on('data', function (chunk) {
str += chunk;
});
// capture the google response and relay it to the original api call.
googleRes.on('end', function () {
resolve(str);
});
}
http.request(options, callback).end();
)};
p1.then(function(googleHtml) {
apiRes.status(200).send(googleHtml);
}
}
Then I can run my app and call the api using Postman at http://localhost:8080/api/gains:
Directly pipe output with apiRes, sample using request :
var request = require("request");
// Entry point to /api/specialday
module.exports = function(apiReq, apiRes, apiNext) {
request.get('http://www.google.fr').pipe(apiRes);
});
I am currently stumped with a problem, where the http.request() just fails/skips to make a request to a given url. I have the following setup
async.waterfall([
firstFunc,
secondFunc,
thirdFunc
], function last(err, result){});
The thirdFunc is where i am making a request and it looks like the following
function thirdFunc(payload, callback){
var responseFromCS = getData(payload);
callback(null, responseFromCS);
}
The getData function looks like the following
function getData(obj){
var curlttogetdata = csConstants.BasePath + csConstants.account_num;
var accountNum = obj.customer.accountnum;
var resData = null;
curlttogetdata = curlttogetdata.replace('${accntNum}', accountNum);
var getData = {
hostname: csURLHost,
path: curlttogetdata,
method:'GET',
headers: {
'X-consumer-id': csConstants.ConsumerIDHeader,
'Content-Type':'application/json'
}
};
var req = http.request(getData, function (res){
var body = '';
res.on('data', function getData(chunk){
body += chunk
});
res.on('end', function parseData(){
try {
resData = JSON.parse(body);
}catch(err){
resData = false;
}
});
});
req.on('error', function csResponseError(err){
resData = false;
});
req.end();
return resData;
}
Now upon debugging, once the debugger reaches http.request(...) it fails to step into callback or make the request and then steps right into req.end(). There is no error returned back. I have looked at my parameters in the getData object a number of times and everything looks fine. Even tested this with a curl and gives back the expected response.
one thing I see immediately is that you are returning resData as if it was a synchronous execution, meaning the httpRequest comes back after resData gets returned from your getData function, which will be null at that point
basically
when your program is executing
it does this
1 -makes http request,
2 -returns resData which is null (because the function executes until the end without stopping)
3 -the http request comes back and now resData has value but your function has already returned
what you need to do is pass a callback function
instead of
var responseFromCS = getData(payload);
you do getData(payload, function(responseFromCS){
//..... do something with the returned data
});
Ok so i believe i know the reasoning behind this. The 'http' node module is an async operation and the function getData that handles this, which is wrapped under thirdFunc in the async operation. I believe this operation gets executed before getData can respond.
So i moved the http.request() into thirdFunc and it works as expected.
app.get('/', function(req, res){
var options = {
host: 'www.google.com'
};
http.get(options, function(http_res) {
http_res.on('data', function (chunk) {
res.send('BODY: ' + chunk);
});
res.end("");
});
});
I am trying to download google.com homepage, and reprint it, but I get an "Can't use mutable header APIs after sent." error
Anyone know why? or how to make http call?
Check out the example here on the node.js doc.
The method http.get is a convenience method, it handles a lot of basic stuff for a GET request, which usually has no body to it. Below is a sample of how to make a simple HTTP GET request.
var http = require("http");
var options = {
host: 'www.google.com'
};
http.get(options, function (http_res) {
// initialize the container for our data
var data = "";
// this event fires many times, each time collecting another piece of the response
http_res.on("data", function (chunk) {
// append this chunk to our growing `data` var
data += chunk;
});
// this event fires *one* time, after all the `data` events/chunks have been gathered
http_res.on("end", function () {
// you can use res.send instead of console.log to output via express
console.log(data);
});
});