如何使用 async/await 从另一个函数访问请求的正文?

Posted

技术标签:

【中文标题】如何使用 async/await 从另一个函数访问请求的正文?【英文标题】:How to access requested body from another function with async/await? 【发布时间】:2019-03-07 10:06:37 【问题描述】:

对不起,通用标题。我对 nodejs 以及 async/await 的想法都很陌生。

所以我有一个快速应用程序,它将 HTTP 获取请求作为回调函数。回调函数获取 body 对象,并将其返回给 getBody 函数。但是当我尝试将 getBody 分配给一个变量时,它返回未定义。

是的,我知道。 getBody 函数在 body 被数据填充之前返回 body,但我只是不知道如何为这个 body 对象编写一个 getter 方法。所以我的问题是,如何在全局范围内同时运行 get 请求和访问 body 对象,这样所有依赖于 body 对象的函数都可以运行而不会出现进一步的问题。

async function getBody (req, res, next) 
    let body = await makeRequest(req, res);
    return body; // THIS RETURNS UNDEFINED



router.get('/', getBody);

function makeRequest (req, res)

    let uri;

    let options = 
        uri: uri,
    ;

    request(options,  function (error, response, body) 
        if (error)
            console.log('error:', error);
         else 
            console.log('Success! statusCode:', response && response.statusCode);
            let jsonObject =  JSON.parse(body);

            return jsonObject;
        
    );

我进行了研究,但找不到有用的资源。提前致谢。

【问题讨论】:

你必须从 makeRequest see here返回一个 Promise 【参考方案1】:

awaitasync 应该和promise 一起使用,这种方法不能返回数据。 return 用于从同步方法返回值。

所以你可以像这样从makeRequest 方法返回一个承诺,

async function getBody(req, res, next) 
    let body = await makeRequest(req, res);
    return body; // NOW BODY IS NOT UNDEFINED, call next() or send response here


router.get('/', getBody);

function makeRequest(req, res) 
    return new Promise((resolve, reject) => 
        let uri;

        let options = 
            uri: uri,
        ;

        request(options, function (error, response, body) 
            if (error) 
                console.log('error:', error);
                return reject(error);
             else 
                console.log('Success! statusCode:', response && response.statusCode);
                let jsonObject = JSON.parse(body);

                return resolve(jsonObject);
            
        );
    )

仅供参考,

let body = await makeRequest(req, next)

等于

makeRequest(req, next).then(body =>  /* YOUR CODE HERE */ )

如果您不知道,您必须处理正文并发送响应,return body 不会将响应发送给客户端。

【讨论】:

虽然您正确地认为需要 Promise 才能使 async/await 工作,但 getBody 在这种情况下作为路由处理程序没有意义,因为它和 makerequest 都没有真正响应请求,也没有调用 next() 没错,我也看到了。但我只是回答了他提出的问题。 是的,谢谢您的回答。正如@Paul 指出的那样, getBody 作为路由处理程序毫无意义,但我什至不想将主体发送到视图。我想从身体中提取信息。这个约定是什么?我应该使用另一个可以在主体上调用函数的中间件吗?另一个笨拙的问题:如何从另一个文件访问正文? 您无法从另一个文件访问正文,您可以将正文传递给另一个函数并确保至少发送一个空响应res.json() 否则您的客户端将挂起【参考方案2】:

好的,@JanithKasun 在完整回答您最初的问题方面做得很好。该答案旨在对此进行一些扩展,以解决您在概念上未在您的问题中明确提出的问题。

据我了解,您正在尝试根据应用处理程序的请求中的信息从第三方资源中获取一些数据。理想情况下,您希望以一种更可重用/可维护的方式分离您的代码。我注意到有问题的代码实际上并没有使用请求或响应对象根本,但我将假设您将有某种参数用于 getBody 函数,以帮助您构建它正在请求的 URI。所以,为此:

// ./lib/get-body.js
const BASE_URI = 'https://example.com/search?q='
async function getBody (query) 
    let body = await makeRequest(query);
    return body;


function makeRequest(query) 
    return new Promise((resolve, reject) => 
        let uri = `$BASE_URIquery`; // results in something like 'https://example.com/search?q=cats'

        let options = 
            uri: uri,
        ;

        // Note: removed console statements here to centralize error handling
        request(options, function (error, response, body) 
            if (error) 
                return reject(error);
             else 
                let jsonObject = JSON.parse(body);
                return resolve(jsonObject);
            
        );
    )

// export the top level function for reuse
module.exports = getBody;

现在,在您的路由代码中:

// ./index.js or wherever
const express = require('express');
const getBody = require('./lib/get-body');

//...whatever other setup...

app.get('/', async (req, res, next) => 
    const query = req.query.terms; // or whatever
    try 
      const body = await getBody(query);
      return res.send(body);
     catch (e) 
        return next(e); // if you don't do this, process hangs forever on error
    
);

// handle the errors. obviously you can do something smart like 
//  figure out the error code and send back something other than a 500 if appropriate. 
app.use((err, req, res, next) => 
  console.error(err);
  res.status(500).send('I am Bender; please insert girder.');
);

希望有帮助!

【讨论】:

以上是关于如何使用 async/await 从另一个函数访问请求的正文?的主要内容,如果未能解决你的问题,请参考以下文章

如何测试使用 async/await 的方法?

如何从使用 Futures/async/await 的流中正确生成?

如何使用 Typescript 在 Vue 3.0 setup() 函数中使用 async/await

如何优雅地处理Async/Await的异常?

async/await的使用

async/await 函数不等待。多个功能不按顺序运行和完成