I'm trying to create a class that will send a post request (login), save the cookie and use that cookie for other operations such as download a file.
I created a local server that that will receive a post http method with user and password in it and a router called /download
that will only be accessed if the user is logged in, otherwise it will return you need to log in
.
The problem: This is the prototype of my class (before hand):
const request = require('request-promise-native')
class ImageDownloader {
constructor(username = null, password = null) {
this.username = username
this.password = password
this.cookie = request.jar()
this.init()
}
init() {
// login and get the cookie
}
download() {
// needs the cookie
}
query() {
// needs the cookie
}
}
As you can see in the code above I need the cookie for two operations that is download
and query
so I though about creating an init
method that will do the initial operations such as login and call it right in the constructor so it will be initialized and put the cookie on the variable this.cookie
to use everywhere, but it doesn't work, it seems that init
is being called after every other method.
const request = require('request-promise-native')
class ImageDownloader {
constructor(username = null, password = null) {
this.username = username
this.password = password
this.cookie = request.jar()
this.init()
}
async init() {
await request({
uri: 'http://localhost/login',
jar: this.cookie,
method: 'post',
formData: {
'username': 'admin',
'password': 'admin'
}
}).catch(e => console.error(e))
}
async download() {
await request({
uri: 'http://localhost/download/image.jpg',
jar: this.cookie
})
.then(b => console.log(b))
.catch(e => console.error(e))
}
query() {
// ...
}
}
const downloader = new ImageDownloader
downloader.download()
It's returning to me that I need to log in (server response)... BUT it works if I do this change:
async download() {
await init() // <<<<<<<<<<<<
await request({
uri: 'http://localhost/download/image.jpg',
jar: this.cookie
})
.then(b => console.log(b))
.catch(e => console.error(e))
}
It only works if I call init
in the download
method.
If I put console.log(this.cookie)
in download
it returns an empty CookieJar
and if I put the same in init
it will return the right cookie but it appears AFTER the execution of download even tho I called it on the constructor before calling download
.
How to solve that? Thank you very much.
@edit
I made the changes that @agm1984 and @Jaromanda X told me but it still doesn't work :(
const request = require('request-promise-native')
class ImageDownloader {
constructor(username = null, password = null) {
this.username = username
this.password = password
this.cookie = request.jar()
this.init().catch(e => console.error(e))
}
async init() {
return await request({
uri: 'http://localhost/login',
jar: this.cookie,
method: 'post',
formData: {
'username': 'admin',
'password': 'admin'
}
})
}
async download() {
return await request({
uri: 'http://localhost/download/image.jpg',
jar: this.cookie
})
}
query() {
// ...
}
}
const downloader = new ImageDownloader
downloader.download()
.then(b => console.log(b))
.catch(e => console.error(e))
But then again... it doesn't work unless I call init
inside download
.
The problem here is that init
is asynchronous. Using it like this:
const downloader = new ImageDownloader;
downloader.download();
The download
function is being executed while init
still did not finish yet.
I wouldn't call the init method in the constructor. What I would do is something like this:
1- remove the init call from the constructor.
2- use the class like this:
const downloader = new ImageDownloader();
downloader.init()
.then(() => downloader.download());
and if you are calling init in an async
function you can do:
await downloader.init();
const result = await downloader.download();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With