How can i send a httpVersion 2.0 request in nodejs?
I have tried almost every request module there is, and all of them is httpVersion 1.1
Get request:
const http2 = require("http2");
const client = http2.connect("https://www.google.com");
const req = client.request({
":path": "/"
});
let data = "";
req.on("response", (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
req.on("data", chunk => {
data += chunk;
});
req.on("end", () => {
console.log(data);
client.close();
});
req.end();
POST Request
let res = "";
let postbody = JSON.stringify({
key: value
});
let baseurl = 'baseurl'
let path = '/any-path'
const client = http2.connect(baseurl);
const req = client.request({
":method": "POST",
":path": path,
"content-type": "application/json",
"content-length": Buffer.byteLength(postbody),
});
req.on("response", (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
req.on("data", chunk => {
res = res + chunk;
});
req.on("end", () => {
client.close();
});
req.end(postbody)
For more details pls see this official documents:
https://nodejs.org/api/http2.html#http2_client_side_example
Since Node.js 8.4.0, you can use built-in http2 module to implement an http2 server. Or if you want to use http2 with Express, here's a great module on npm: spdy.
Here're some code from express-spdy:
const fs = require('fs');
const path = require('path');
const express = require('express');
const spdy = require('spdy');
const CERTS_ROOT = '../../certs/';
const app = express();
app.use(express.static('static'));
const config = {
cert: fs.readFileSync(path.resolve(CERTS_ROOT, 'server.crt')),
key: fs.readFileSync(path.resolve(CERTS_ROOT, 'server.key')),
};
spdy.createServer(config, app).listen(3000, (err) => {
if (err) {
console.error('An error occured', error);
return;
}
console.log('Server listening on https://localhost:3000.')
});
Just to add more note cause this is the main point behind using HTTP2 in case you have multiple requests to the same endpoint
var payload1 = JSON.stringify({});
var payload2 = JSON.stringify({});
const client = http2.connect('server url');
const request = client.request({
":method": "POST",
':path': 'some path',
'authorization': `bearer ${token}`,
"content-type": "application/json",
});
request.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
request.setEncoding('utf8');
let data = ''
request.on('data', (chunk) => { data += chunk; });
request.on('end', () => {
console.log(`\n${data}`);
client.close();
});
// send as many request you want and then close the connection
request.write(payload1)
request.write(payload2)
request.end();
Hope to help someone
Related
I am learning to use http post and trying to wait for it to end using promise. But I can't get it to work, please help:
var http = require('http');
const auth = () => {
var post_data = JSON.stringify({
"username": "aaa",
"password": "bbb"
});
const options = {
host: 'http://1.1.1.1',
path: '/v1/authentication',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
const req = http.request(options, (res) => {
res.setEncoding('utf8');
var body = '';
res.on('data', d => {
body += chunk;
});
res.on('end', function() {
console.log("Response body", body);
});
});
req.on('error', error => {
console.error("error", error);
});
req.write(post_data)
req.end();
return Promise.resolve("!!");
};
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
return auth().then((res)=>{
res.status(200).send(res);
});
};
Entry point is the hellWorld function. What should I do to wait for the http post to finish and get the response result using promise?
here i did some for get api call.
try {
const auth = () => {
return new Promise((resolve, reject) => {
const options = {
host: 'api.github.com',
path: '/orgs/nodejs',
port: 443,
method: 'GET',
headers: {
'User-Agent': 'request'
}
};
const req = https.request(options, (res) => {
res.setEncoding('utf8');
res.on('data', d => {
resolve(d)
});
});
req.on('error', error => {
console.error("error", error);
});
req.end();
})
};
const data = await auth()
console.log('should execute first', data)
console.log('should executed after http call')
} catch (e) {
console.log(e)
}
you can modify above code with your, just you have to wrap your http call inside Promises.
comment down if any its a solution, and mark as a solution
How can I send Id and password means basic authentication to below code. I mean where I need to put id/pass in below code? My API needs basic authentication
const https = require('https');
https.get('https://rws322s213.infosys.com/AIAMFG/rest/v1/describe', (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
console.log(JSON.parse(data).explanation);
});
}).on("error", (err) => {
console.log("Error: " + err.message);
});
To request Basic authentication, a client passes a http Authorization header to the server. That header takes the form
Authorization: Basic Base64EncodedCredentials
Therefore, your question is "how to pass a header with a https.get() request?"
It goes in options.headers{} and you can put it there like this:
const encodedCredentials = /* whatever your API requires */
const options = {
headers: {
'Authorization' : 'Basic ' + encodedCredentials
}
}
const getUrl = https://rws322s213.infosys.com/AIAMFG/rest/v1/describe'
https.get (getUrl, options, (resp) => {
/* handle the response here. */
})
const https = require('https');
const httpsAgent = new https.Agent({
rejectUnauthorized: false,
});
// Allow SELF_SIGNED_CERT, aka set rejectUnauthorized: false
let options = {
agent: httpsAgent
}
let address = "10.10.10.1";
let path = "/api/v1/foo";
let url = new URL(`https://${address}${path}`);
url.username = "joe";
url.password = "password123";
let apiCall = new Promise(function (resolve, reject) {
var data = '';
https.get(url, options, res => {
res.on('data', function (chunk){ data += chunk })
res.on('end', function () {
resolve(data);
})
}).on('error', function (e) {
reject(e);
});
});
try {
let result = await apiCall;
} catch (e) {
console.error(e);
} finally {
console.log('We do cleanup here');
}
I have an azure function with this line of code.
var myReq = https.request(options, function(res) {
context.log('STATUS: ' + res.statusCode);
context.log('HEADERS: ' + JSON.stringify(res.headers));
body += res.statusCode
res.on('data', function (chunk) {
context.log('BODY: ' + chunk);
});
});
myReq.on('error', function(e) {
context.log('problem with request: ' + e.message);
});
myReq.write(postData);
myReq.end();
But my code seems to just skip this part of code, with no errors. I am new to Azure and node.js so I might have missed some basic parts in setting this up.
Any ideas?
Edit:
Here is my full code
const https = require('https');
const querystring = require('querystring');
module.exports = async function (context, req) {
if (req.query.accessCode || (req.body && req.body.accessCode)) {
context.log('JavaScript HTTP trigger function processed a request.');
var options = {
host: 'httpbin.org',
port: 80,
path: '/post',
method: 'POST'
};
var postData = querystring.stringify({
client_id : '1234',
client_secret: 'xyz',
code: req.query.accessCode
});
var body = "";
var myReq = https.request(options, function(res) {
context.log('STATUS: ' + res.statusCode);
context.log('HEADERS: ' + JSON.stringify(res.headers));
body += res.statusCode
res.on('data', function (chunk) {
context.log('BODY: ' + chunk);
});
});
myReq.on('error', function(e) {
context.log('problem with request: ' + e.message);
});
myReq.write(postData);
myReq.end();
context.log("help");
context.res = {
status: 200,
body: "Hello " + (body)
};
} else {
context.res = {
status: 400,
body: "Please pass a name on the query string or in the request body"
};
}
};
Ideally it should work. You can also try using request module like below
const request = require('request');
request('http://www.google.com', function (error, response, body) {
console.error('error:', error); // Print the error if one occurred
console.log('statusCode:', response && response.statusCode); // Print the response status code if a response was received
console.log('body:', body); // Print the HTML for the Google homepage.
});
Try and see if it helps.
Solved by doing await properly. Used this as guide.
var https = require('https');
var util = require('util');
const querystring = require('querystring');
var request = require('request')
module.exports = async function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
/*if (req.query.name || (req.body && req.body.name)) {*/
var getOptions = {
contentType: 'application/json',
headers: {
'Authorization': <bearer_token>
},
};
var postData = {
"key": "value"
};
var postOptions = {
method: 'post',
body: postData,
json: true,
url: <post_url>,
headers: {
'Authorization': <bearer_token>
},
};
try{
var httpPost = await HttpPostFunction(context, postOptions);
var httpGet = await HttpGetFunction(context, <get_url>, getOptions);
return {
res: httpPost
};
}catch(err){
//handle errr
console.log(err);
};
};
async function HttpPostFunction(context, options) {
context.log("Starting HTTP Post Call");
return new Promise((resolve, reject) => {
var data = '';
request(options, function (err, res, body) {
if (err) {
console.error('error posting json: ', err)
reject(err)
}
var headers = res.headers;
var statusCode = res.statusCode;
//context.log('headers: ', headers);
//context.log('statusCode: ', statusCode);
//context.log('body: ', body);
resolve(body);
})
});
};
async function HttpGetFunction(context, url, options) {
context.log("Starting HTTP Get Call");
return new Promise((resolve, reject) => {
var data = '';
https.get(url, options, (resp) => {
// A chunk of data has been recieved.
resp.on('data', (chunk) => {
data += chunk;
})
// The whole response has been received. Print out the result.
resp.on('end', () => {
resolve(JSON.parse(data));
});
}).on("error", (err) => {
console.log("Error: " + err.message);
reject(err.message);
});
});
};
I have the following app to download productAds from amazons Sponsored Products API
Docs: https://advertising.amazon.com/API/docs/reference/reports
When I try to fun it, I get the response from requesting the report, and obtain a file in an s3 Bucket.
server is running at localhost:3000
{"reportId":"amzn1.clicPI.v1.p7.5B7EE.d141f-e5-4b-a8-6a4e712","status":"SUCCESS","statusDetails":"Report has been successfully generated","location":"https://advertising-api.amazon.com/v1/reports/amzn1.clsAPI.v1.p7.5B7EE.d151f-e5-4b-a8-699e712/download","fileSize":22}
Next I try to download the report
and the repose I get the following erro:
donwloading <?xml version="1.0" encoding="UTF-8"?>
<Error><Code>InvalidArgument</Code><Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message><ArgumentName>Authorization</ArgumentName><ArgumentValue>bearer Atza|IwEBIJvCt20TUi122srkN4JCOdUxlBNuLJBrtbIGF9x5QbKG67f-K-0L4RkLzeyouXWy_U_-VscaCe1aFqOJK55X9Mu2X6nwWkAWRyhc6cCMfPjKpyyVjKtPqC8Plme84om1dqtmIqC93yUVc_clHimQqmnl262te2EXyUhYoVQg8hK2nlDG67Iw7xjsLK4rgl3E4RR36DHnZkEOnVQZtfjIkIbcYtsCSAdpRZRazF4FQfpS-jHvMlwuH8TZfY9tRpmBEx5fjJw1WZ14Dejqti23mZ7yt-MjNkUuD-DdPXs3fek1ZJePlHEVzcI2y_WzCnwJnoSVp5a5w1WgNco8YqEGEuLsT9S0dxQRluTiw8f4b4lx2FFFm9jz0K7pqo1Mvs6DZOVCDJzE-xJ_VLlWoE5QDMUAMor4AEQH44_0NWBjJDrYaVvn1vZLCER1uxW4jgr127W5yXaj4y1vj_vADwFq9a3330hAc73EWwL6FFSfoTQZyNc4Fh1d3DXfVHpXFk6cv0bHt4cV_OotGwGHat5fv75VHX5K3al3Xd5-QJv2cTiQ9srY5oqKsdbxptGaxAdrdMQaUlFHhyHEGbwED9xYoCw6-IauN15gvMAei9wz2kzRCA</ArgumentValue><RequestId>BDCE812C4363E9D2</RequestId><HostId>4ixH24mPtMBt+FDnI3rM9UJP95toaNBmmR1v0uQJ5XkyiXbtLEuZ8d+vDI0+gquwhn6/Fkz6/+o=</HostId></Error>
Here is the app. How can I download the report and pass the headers correctly? I found this repo in PHP that has the download function: https://github.com/dbrent-amazon/amazon-advertising-api-php/blob/master/AmazonAdvertisingApi/Client.php
const express = require('express')
const app = express();
const request = require('request');
const moment = require('moment');
const fs = require('fs')
const path = require('path')
const config = require('./config')
const auth = require('./helpers/auth');
const cron = require('./helpers/cron');
const con = require('./helpers/database');
const getProfiles = (headers) => {
return new Promise((resolve, reject) => {
request({
url: config.ad_url + '/v1/profiles',
method: "GET",
headers: headers
}, (err, httpResponse, body) => {
if (err) {
reject(err);
}
resolve(body);
});
})
}
const createReport = (params, recordType, headers) => {
return new Promise((resolve, reject) => {
request({
url: config.ad_url + '/v1/' + recordType + '/report',
method: "POST",
headers: headers,
json: params
}, (err, httpResponse, body) => {
if (err) {
reject(err);
}
resolve(body);
});
})
}
const getReport = (reportId, headers) => {
return new Promise((resolve, reject) => {
request({
url: config.ad_url + '/v1/reports/' + reportId,
method: "GET",
headers: headers
}, (err, httpResponse, body) => {
if (err) {
reject(err);
}
resolve(body);
});
})
}
function download(fileUrl, apiPath, callback) {
var url = require('url'),
http = require('http'),
p = url.parse(fileUrl),
timeout = 10000;
var file = fs.createWriteStream(apiPath);
var timeout_wrapper = function (req) {
return function () {
console.log('abort');
req.abort();
callback("File transfer timeout!");
};
};
console.log('before');
var request = http.get(fileUrl).on('response', function (res) {
console.log('in cb');
var len = parseInt(res.headers['content-length'], 10);
var downloaded = 0;
res.on('data', function (chunk) {
file.write(chunk);
downloaded += chunk.length;
process.stdout.write("Downloading " + (100.0 * downloaded / len).toFixed(2) + "% " + downloaded + " bytes" + isWin ? "\033[0G" : "\r");
// reset timeout
clearTimeout(timeoutId);
timeoutId = setTimeout(fn, timeout);
}).on('end', function () {
// clear timeout
clearTimeout(timeoutId);
file.end();
console.log(file_name + ' downloaded to: ' + apiPath);
callback(null);
}).on('error', function (err) {
// clear timeout
clearTimeout(timeoutId);
callback(err.message);
});
});
// generate timeout handler
var fn = timeout_wrapper(request);
// set initial timeout
var timeoutId = setTimeout(fn, timeout);
}
const recordType = 'productAds';
const campaignType = 'sponsoredProducts';
const reportDate = moment().format('YYYYMMDD');
const metrics = 'campaignId,sku,currency,attributedConversions1d';
const reportParam = {
campaignType: campaignType,
// segment: "query",
reportDate: reportDate,
metrics: metrics
}
auth().then(res => {
const headers = {
'Content-Type': 'application/json',
'Authorization': config.token_type + ' ' + res.access_token,
'Amazon-Advertising-API-Scope': '196354651614',
}
// getProfiles(headers).then(res => {})
const reportId = 'amzn1.clicksAI.1.p.5B057EE.d41f-e5-4a-a8-699e712';
getReport(reportId, headers).then(res => {
console.log(res)
const file = JSON.parse(res);
// console.log(file.location )
// download
request({
url: file.location,
method: 'GET',
headers: {
'Authorization': headers.Authorization,
'Amazon-Advertising-API-Scope': '196335474',
'Allow': 'GET, HEAD, PUT, DELETE'
}
}, (err, response, body) => {
console.log('donwloading', body)
})
})
createReport(reportParam, recordType, headers).then(res => {
const reportId = 'amzn1.clicksI.v1.p7.5B07EE.d1541f-e5-eb-a68-6996e712';
})
})
app.listen(3000, function(err) {
console.log("server is running at localhost:3000");
})
This is caused by sending the "Authorization" header to S3 and it doesn't want that. The reason is because the /download response from the API is a 307 redirect so the client you are using is redirecting with full API headers. To get around this, prevent your client from following redirects and parse the S3 location from the header of the response instead.
I am attempting to make a request to another API from a Lambda. I am finding that using the NodeJS http and https modules allow for GET requests but any others (e.g. POST) do not work; POST coincidentally is the only method I need to work for the service I am attempting to call.
Here is a working example of Lambda performing a GET and receiving a 200 response:
const https = require('https')
function handler(event, context, callback) {
const options = {
hostname: 'encrypted.google.com'
}
https
.get(options, (res) => {
console.log('statusCode:', res.statusCode);
res.on('end', callback.bind(null, null))
})
.on('error', callback);
}
exports.handler = handler
So that proves that he request is allowed. However, if the script attempts to make the same request using the .request() method of the https (or https) lib/module the request never finishes and the Lambda times out.
const https = require('https')
function handler(event, context, callback) {
const options = {
hostname: 'encrypted.google.com',
method: 'GET'
}
https
.request(options, (res) => {
console.log('statusCode:', res.statusCode);
res.on('end', callback.bind(null, null))
})
.on('error', callback);
}
exports.handler = handler
I don't know what I am doing wrong. The call https.request() silently fails - doesn't throw an error - and nothing is reported in the log.
The problem was that I was never completing the request with req.end().
const https = require('https')
function handler(event, context, callback) {
const options = {
hostname: 'encrypted.google.com',
method: 'GET'
}
https
.request(options, (res) => {
console.log('statusCode:', res.statusCode);
res.on('end', callback.bind(null, null))
})
.on('error', callback)
.end(); // <--- The important missing piece!
}
exports.handler = handler
Please try this one if your API is HTTPS,
var url = 'HTTPS URL HERE';
var req = https.get(url, (res) => {
var body = "";
res.on("data", (chunk) => {
body += chunk
});
res.on("end", () => {
var result = JSON.parse(body);
callBack(result)
});
}).on("error", (error) => {
callBack(err);
});
}
And if it is HTTP then,
var url = 'HTTP URL HERE';
var req = http.get(url, (res) => {
var body = "";
res.on("data", (chunk) => {
body += chunk
});
res.on("end", () => {
var result = JSON.parse(body);
callBack(result)
});
}).on("error", (error) => {
callBack(err);
});
}
Please don't fogot to add package require('https') / require('http')
The POST method is done by the request method.
This is the lambda code:
const https = require('https');
const options = {
hostname: 'Your host name',
path: '/api/v1/Login/Login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body : JSON.stringify({
'email': 'hassan.uzair9#gmail.com',
'password': 'Asdf1234.',
})
};
var result;
try{
result = await https.request(options);
console.log("result.....",result);
}catch(err){
console.log("err......",err);
}