admin管理员组

文章数量:1292121

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.

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.

Share Improve this question edited Oct 8, 2017 at 0:02 vajehu asked Oct 7, 2017 at 23:39 vajehuvajehu 1811 gold badge2 silver badges10 bronze badges 12
  • @JaromandaX I don't understand why I would return anything as the operations inside init and download doesn't need to be shared anywhere and the request-promise-native will put the jar in the this.cookie for me (what I need), but the thing is the order things are running. Adding await init() in download is behaving like "I have to wait for init to finish and then continue" (something like that), but as I called this.init in the constructor I though it wouldn't be needed. – vajehu Commented Oct 7, 2017 at 23:50
  • Sorry, yeah, I misread your code – Jaromanda X Commented Oct 8, 2017 at 0:02
  • as I said, I misread your code, ignore my changes :p - most of them are not required as I screwed up my knowledge of async/await :p – Jaromanda X Commented Oct 8, 2017 at 0:05
  • That is okay, you tried to help and I fully understand what you mean. Thank you anyway. – vajehu Commented Oct 8, 2017 at 0:06
  • the problem now is that download wont wait for init – Jaromanda X Commented Oct 8, 2017 at 0:07
 |  Show 7 more ments

1 Answer 1

Reset to default 2

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();

本文标签: javascriptES6 asyncawait in classesStack Overflow