all. I created a function to get the response headers of a request I made using https from node.js. But I am having trouble returning the headers value for this function.. the function is written bellow. Could you guys help me?
function getHeaders() {
let headers = {};
var options = {
method: 'get',
host: 'www.google.com',}
const req = https.request(options, (res) => {
let body = '';
headers = res.headers;
res.on('data', (chunk) => {
body = chunk;
})
res.on('end', () => {
console.log('Body: ', body);
})
})
req.end();
return headers;
};
const headers = getHeaders();
CodePudding user response:
.request
is a stream, and node.js runs asynchronously, so it returns headers, before it's assigned and before the request is done
you need to wait for request to finish, and then return values you need, which can be achieved with async/await
so, you could wrap request in a promise, and resolve when the request is done, and when calling the function use async/await
try this:
function getHeaders() {
// return a promise
return new Promise((resolve) => {
let headers = {};
var options = {
method: 'get',
host: 'www.google.com',
}
const req = https.request(options, (res) => {
let body = '';
headers = res.headers;
res.on('data', (chunk) => {
body = chunk;
})
res.on('end', () => {
console.log('Body: ', body);
// resolve when request is done
resolve(headers);
})
})
req.end();
});
};
// async function, awaits request to finish/resolve
(async() => {
// get the promise and wait until it resolves
const headers = await getHeaders();
console.log(headers);
})();
CodePudding user response:
The problem
Your problem is that https.request()
executes asynchronously thus the request is made and the next instructions are immediately executed which leads to the initial value of headers
which is {}
being returned.
As network is slower than executing the next instruction the callback which would set headers
to the actual response headers is executed after you have already returned and therefore does not affect the result. You can test this by printing the result of getHeaders()
. You will notice that the result of getHeaders() will always be printed before the request body is printed. See this example based on your code with some minor edits to make the output clearer.
function getHeaders() {
let headers = {};
var options = {
method: 'get',
host: 'www.google.com',
}
const req = https.request(options, (res) => {
let body = '';
headers = res.headers;
// print response headers as soon as they are available
console.log("Response header:", res.headers)
res.on('data', (chunk) => {
body = chunk;
})
res.on('end', () => {
// for clarity of output omit this line
// console.log('Body: ', body);
})
})
req.end();
return headers;
};
const headers = getHeaders();
// print return value of getHeaders()
console.log("Return value of getHeaders():", headers);
Expected output:
Return value of getHeaders(): {}
Response header: {
date: 'Tue, 08 Mar 2022 15:22:37 GMT',
expires: '-1',
'cache-control': 'private, max-age=0',
'content-type': 'text/html; charset=ISO-8859-1',
...
'transfer-encoding': 'chunked'
}
The solution
What you need to do is wait until the headers are available and as soon as they are return the headers.
One way to do this is by using Promises and async/ await
. You will then see that the return value of getHeaders()
will always be printed after the response body.
function getHeaders() {
// return a Promise instead of headers themselves
return new Promise((resolve, reject) => {
let headers = {};
var options = {
method: 'get',
host: 'www.google.com',
}
const req = https.request(options, (res) => {
let body = '';
headers = res.headers;
console.log("Response header:", res.headers)
res.on('data', (chunk) => {
body = chunk;
})
res.on('end', () => {
// for clarity of output omit this line
// console.log('Body: ', body);
// body is printed and headers are available => resolve promise
resolve(headers)
})
})
// in case the request fails for some reason reject the Promise
req.on('error', err => {
reject(err)
})
req.end();
// with resolve() headers have already been made available so this return should be deleted
// return headers;
})
};
// now use await (await can only be used in an asynchronous function so wrap it in one)
(async () => {
try {
const headers = await getHeaders();
console.log("Return value of getHeaders():", headers);
} catch (error) {
// promise was rejected => do some meaningful error handling here
console.log(error)
}
})();
Expected result:
Response header: {
date: 'Tue, 08 Mar 2022 15:46:36 GMT',
expires: '-1',
'cache-control': 'private, max-age=0',
'content-type': 'text/html; charset=ISO-8859-1',
...
'transfer-encoding': 'chunked'
}
Return value of getHeaders(): {
date: 'Tue, 08 Mar 2022 15:46:36 GMT',
expires: '-1',
'cache-control': 'private, max-age=0',
'content-type': 'text/html; charset=ISO-8859-1',
...
'transfer-encoding': 'chunked'
}
There also is a whole thread on this topic already so you might wanna take a look at it.