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
。
这个该怎么样解决呢?
为了使 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;
解释
-
改造
cURL
函数:- 使用
new Promise
包装http.request
操作。 - 在
res.on('data')
中累积数据。 - 在
res.on('end')
中调用resolve
并传递累积的数据。 - 处理请求错误,使用
reject
抛出错误。
- 使用
-
修改路由处理函数:
- 使用
async
关键字标记路由处理函数。 - 使用
await
等待cURL
返回的结果。 - 将结果传递给渲染模板。
- 使用
-
模板渲染:
- 在模板中直接使用
{ cURL: result }
渲染结果。
- 在模板中直接使用
通过这种方式,我们可以确保 http.request
完成后再返回结果,并且可以在 Express 路由中正确处理这些结果。
我来抛砖引玉一下,首先http.request
是异步的,也就是说res.render
的时候cURL
并没有返回结果,所以是undefined
。
我的解决办法是使用一个res
队列,每次请求不返回内容,只是触发cURL
,然后在cURL
的回调里使用对应的res.render
。
或者把http.request
改成同步的,如eventproxy
、q
、promise
,具体实现留给楼下。
这个东西,使用队列不好,使用“请求池”的办法好些,哪个先到 ,哪个先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;
解释
-
定义异步函数:
cURL
函数被定义为async
,以便可以使用await
关键字。cURL
返回一个Promise
,这样我们可以在调用它时等待它的完成。
-
处理 HTTP 请求:
- 在
http.request
回调中,我们收集所有响应数据并将其存储在一个变量中。 - 当响应结束 (
res.on('end')
) 时,我们使用resolve(data)
来解析 Promise 并返回结果。
- 在
-
处理错误:
- 在请求过程中如果发生错误 (
req.on('error')
),我们使用reject(e)
来拒绝 Promise 并返回错误信息。
- 在请求过程中如果发生错误 (
-
路由处理:
- 在路由处理函数中,我们使用
await cURL()
来等待cURL
函数的结果。 - 如果成功获取到数据,则将其渲染到模板中。
- 如果发生错误,则返回一个错误消息。
- 在路由处理函数中,我们使用
通过这种方式,我们可以确保 http.request
完成后再返回结果,从而避免返回 undefined
的问题。