Nodejs 如何才能够让一个function中的http.request执行结束后返回结果

Nodejs 如何才能够让一个function中的http.request执行结束后返回结果

我想写一个类似于 cURL 的 function,并将结果通过 Express 的 Router 传递到网页上显示出来。 下面是 router/index.js 中的代码:

var express = require('express');
var router = express.Router();
var http = require("http");

/* cURL Module Test */
function cURL() {
    var CURL_OPTION = {
        hostname: 'fcsys.tk',
        port: 80,
        path: '/ip.php',
        method: 'GET'
    };
    http.request(CURL_OPTION, function(res) {
        console.log('STATUS: ' + res.statusCode);
        console.log('HEADERS: ' + JSON.stringify(res.headers));
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            console.log('BODY: ' + chunk);
            global.abc = chunk;
        });
    }).end();
    return global.abc;
}

/* GET home page. */
router.get('/', function(req, res) {
  res.render('index', {cURL: cURL});
});

module.exports = router;

下面是网页部分的代码,只是取得 cURL 的返回值而已:

<p>cURL: <%=cURL()%></p>

但是打开页面会无法得到返回值,是 undefined

这个该怎么样解决呢?


4 回复

为了使 http.request 执行完毕后能够正确返回结果并被 Express 路由处理,我们需要确保 http.request 的异步操作完成后再返回结果。可以通过回调函数、Promise 或者 async/await 来实现这一点。

下面是使用 async/await 和 Promise 的示例代码:

修改 cURL 函数

我们将 cURL 函数改造成返回一个 Promise,这样可以使用 async/await 更方便地处理异步操作。

// router/index.js
var express = require('express');
var router = express.Router();
var http = require("http");

/* cURL Module Test */
function cURL() {
    return new Promise((resolve, reject) => {
        var CURL_OPTION = {
            hostname: 'fcsys.tk',
            port: 80,
            path: '/ip.php',
            method: 'GET'
        };

        let data = '';
        const req = http.request(CURL_OPTION, function(res) {
            console.log('STATUS: ' + res.statusCode);
            console.log('HEADERS: ' + JSON.stringify(res.headers));
            res.setEncoding('utf8');

            res.on('data', function(chunk) {
                data += chunk;
            });

            res.on('end', function() {
                resolve(data);
            });
        });

        req.on('error', function(e) {
            reject(e.message);
        });

        req.end();
    });
}

/* GET home page. */
router.get('/', async function(req, res) {
    try {
        const result = await cURL();
        res.render('index', { cURL: result });
    } catch (error) {
        res.status(500).send('Error: ' + error);
    }
});

module.exports = router;

解释

  1. 改造 cURL 函数

    • 使用 new Promise 包装 http.request 操作。
    • res.on('data') 中累积数据。
    • res.on('end') 中调用 resolve 并传递累积的数据。
    • 处理请求错误,使用 reject 抛出错误。
  2. 修改路由处理函数

    • 使用 async 关键字标记路由处理函数。
    • 使用 await 等待 cURL 返回的结果。
    • 将结果传递给渲染模板。
  3. 模板渲染

    • 在模板中直接使用 { cURL: result } 渲染结果。

通过这种方式,我们可以确保 http.request 完成后再返回结果,并且可以在 Express 路由中正确处理这些结果。


我来抛砖引玉一下,首先http.request是异步的,也就是说res.render的时候cURL并没有返回结果,所以是undefined。 我的解决办法是使用一个res队列,每次请求不返回内容,只是触发cURL,然后在cURL的回调里使用对应的res.render。 或者把http.request改成同步的,如eventproxyqpromise,具体实现留给楼下。

这个东西,使用队列不好,使用“请求池”的办法好些,哪个先到 ,哪个先res.send出去

要解决这个问题,我们需要确保 http.request 完成后才能返回结果。由于 http.request 是异步操作,我们可以使用回调函数、Promise 或 async/await 来处理这种情况。

以下是使用 async/await 的解决方案,因为它更加简洁易读:

修改后的代码

router/index.js

var express = require('express');
var router = express.Router();
var http = require("http");

/* cURL Module Test */
async function cURL() {
    return new Promise((resolve, reject) => {
        var CURL_OPTION = {
            hostname: 'fcsys.tk',
            port: 80,
            path: '/ip.php',
            method: 'GET'
        };

        var req = http.request(CURL_OPTION, function(res) {
            let data = '';
            res.on('data', function(chunk) {
                data += chunk;
            });

            res.on('end', function() {
                resolve(data);
            });
        });

        req.on('error', function(e) {
            reject(e);
        });

        req.end();
    });
}

/* GET home page. */
router.get('/', async function(req, res) {
    try {
        const result = await cURL();
        res.render('index', { cURL: result });
    } catch (err) {
        res.status(500).send('Error fetching data.');
    }
});

module.exports = router;

解释

  1. 定义异步函数

    • cURL 函数被定义为 async,以便可以使用 await 关键字。
    • cURL 返回一个 Promise,这样我们可以在调用它时等待它的完成。
  2. 处理 HTTP 请求

    • http.request 回调中,我们收集所有响应数据并将其存储在一个变量中。
    • 当响应结束 (res.on('end')) 时,我们使用 resolve(data) 来解析 Promise 并返回结果。
  3. 处理错误

    • 在请求过程中如果发生错误 (req.on('error')),我们使用 reject(e) 来拒绝 Promise 并返回错误信息。
  4. 路由处理

    • 在路由处理函数中,我们使用 await cURL() 来等待 cURL 函数的结果。
    • 如果成功获取到数据,则将其渲染到模板中。
    • 如果发生错误,则返回一个错误消息。

通过这种方式,我们可以确保 http.request 完成后再返回结果,从而避免返回 undefined 的问题。

回到顶部