JavaScript,使用Promise同时进行POST和GET请求

3
背景:我有一个需要进行小调试的函数,它涉及到API请求(POST、GET)和Promises。在过去的几天里,我一直在尝试弄清楚异步函数的工作原理,结果发现不可能(或者说是听说)直接从这样的函数中返回值给同步函数。
我的最初想法是创建一个POST请求函数,该函数返回访问令牌,我可以将其插入到我的GET函数的授权标头中(只要提供了令牌,它就能完美地工作)。然而,从我的发现来看,我不能在两个独立的方法上执行此操作,因为POST请求在函数外返回undefined。所以现在我的想法是将GET请求包含在POST中,以便可以直接传递访问令牌,而不需要任何方法调用。我试图使用Promises来做到这一点,虽然我对它们不太熟悉,但也能够理解一些。我期望的是,我可以调用httpGetData()函数,该函数首先获取令牌,然后将其传递给一个.then()部分,该部分应该返回实际数据或[object Promise]而不是undefined。
问题:问题在于,当我调用httpGetData()函数时,它返回undefined,但是我的console.log(result[0])清楚地显示GET请求已经获取了我想要的数据。我想知道是否有一种调整方法,可以使我的代码返回这些数据(console.log对我来说毫无用处,除了查看API请求的后台情况)。我看到一些类似于这样的SO问题是通过在.then()中返回值来解决的,但是我的尝试都返回undefined。
我附上了输出的截图。请记住,这是一个Alexa技能Lambda代码,因此返回出现在.speak()之后,而console.log则显示在下面。
function httpGetData() {

  var promise1 = new Promise(((resolve, reject) => {
    var options = {
      method: "POST", // POST request intended to get access token
      host: 'hostinfo',
      path: "pathinfo",                                                        
      headers: {
        "content-type": "stuff here",
        "cache-control": "no-cache",
     }
  };

  var request = http.request(options, function (response) {
    var returnData = [];

    response.on("data", function (chunk) {
      returnData += chunk;
    });

    response.on("end", function () {
      var data = JSON.parse(returnData);
      var accessToken = data.access_token; // the access token value of the POST api request like "039509544932n3249fc21232nc32423nci"
      resolve(accessToken);
    });

    response.on('error', (error) => {
      reject(error);
    });
  });

  request.write("------stuff: form-data; name=\"client_secret\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"client_id\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"grant_type\"\r\n\r\nclient_credentials\r\n------stuff");
  request.end();

  }));

  promise1.then(function(value) {
      return new Promise(((resolve, reject) => {
        var options = {
          method: "GET", //this is a GET request so it's intended to get usable data using access token
          host: 'hostinfo',
          path: "pathinfo",                
          headers: {
            "content-type": "stuff here",
            "Authorization": "Bearer " + value, // value is the access token that was resolved earlier ("039509544932n3249fc21232nc32423nci") so I'm trying to concatonate this to the authorization header
            "cache-control": "no-cache",
         }
    };

      var request = http.request(options, function (response) {
        var returnData = [];

        response.on("data", function (chunk) {
          returnData += chunk;
        });

        response.on("end", function () {
          console.log(value); //this is the line that prints access token in screenshot
          resolve(JSON.parse(returnData));
        });

        response.on('error', (error) => {
          reject(error);
        });
      });

      request.write("------stuff: form-data; name=\"client_secret\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"client_id\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"grant_type\"\r\n\r\nclient_credentials\r\n------stuff");
      request.end();

        }))
  }).then((result) => {
            console.log('hello');
            return result; //I'm not sure here but wanted to return the result 
            }).then((result) => {
                  console.log(result[0]); // just a check which shows that result[0] actually executes and can be printed as shown in screenshot
                  return result[0]; //other desperate attempt


});


}// httpGetData() function ends here

返回图片

控制台日志图片


如果我正确理解你的代码,你在这里遇到的问题是,虽然你调用了 return result[0],但它返回的是 .then 中声明的函数的值,而不是 httpGetData 的值。实际上,在 .then 到达之前,httpGetData 已经执行完毕了。我唯一能想到的办法就是让 httpGetData 接受一个回调函数。 - OllysCoding
这里有一个快速问题,你是否只是想让函数返回未完成的 Promise ,以便稍后在其他地方等待它呢?如果是的话,你可以在函数末尾添加 return promise1。因为你的函数应该返回实际数据或 [object Promise] 而不是 undefined。 - OllysCoding
但是如果.then()没有等待httpGetData()函数的承诺数据,它有什么用处呢?此外,承诺和回调是分开的东西还是应该一起使用?我之前尝试过像httpGetData(callback)这样使用回调,但我一直收到“类型错误:callback不是一个函数”的提示,这对我来说很麻烦,因为我是新手。 - Abenezer Ayana
是的,我想返回未决承诺,因为有一个不同的异步/等待函数正在等待获取该值。 - Abenezer Ayana
1
@AbenezerAyana 那个单一的函数看起来就像 return getAccessToken().then(token => getResource(token));。当然,你也可以将这两个函数内联,但是分开理解和实现会更容易些。 - Bergi
显示剩余7条评论
1个回答

1
我最终感谢 @Bergi 的帮助解决了这个问题。虽然这个答案可以缩短,但我想发布它作为一个选项。Bergi 建议的是,我们可以将 POST 和 GET 请求分开,并使用另一个函数同时执行它们。在下面的代码中,httpToken() 执行 POST 请求并返回访问令牌。httpResource(accessToken) 函数执行 GET 请求,其中将使用 accessToken 参数。另一个函数 finalData() 将帮助我们同时进行 POST 和 GET 请求,因此返回一个[object Promise] 而不是 undefined,我们可以访问它。我们的最后一步是拥有一个 async/await 函数 (retrieveInfo()),它将使用 finalData() 来获取我们请求的响应。享受!
function httpToken() {
  return new Promise(((resolve, reject) => {
    var options = {
      method: "POST",
      host: 'hostinfo',
      path: "pathinfo",                                                        
      headers: {
        "content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
        "cache-control": "no-cache",
     }
  };

  var request = http.request(options, function (response) {
    var returnData = [];

    response.on("data", function (chunk) {
      returnData += chunk;
    });

    response.on("end", function () {
      var data = JSON.parse(returnData);
      var accessToken = data.access_token;
      resolve(accessToken); //resolving access token (can be changed to resolve(data) to include timestamp etc)
    });

    response.on('error', (error) => {
      reject(error);
    });
  });

  request.write("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n"client secret here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n"client id here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n"grant type here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
  request.end();

  }));
}


function httpResource(accessToken){
      return new Promise(((resolve, reject) => {
        var options = {
          method: "GET",
          host: 'hostinfo',
          path: "pathinfo",                                                       
          headers: {
            "content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
            "Authorization": "Bearer " + accessToken,
            "cache-control": "no-cache",
         }
    };

      var request = http.request(options, function (response) {
        var returnData = [];

        response.on("data", function (chunk) {
          returnData += chunk;
        });

        response.on("end", function () {
          resolve(JSON.parse(returnData));
        });

        response.on('error', (error) => {
          reject(error);
        });
      });

      request.write("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n"client secret here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n"client id here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n"grant type here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
      request.end();


    }));
}

function finalData()
{
  return httpToken().then(token => httpResource(token));
}

async function retrieveInfo()
{
    response = await finalData(); //response will have the data returned from our GET request using finalData()

    //do stuff with response...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接