简单问题: Nodejs http.get() 如何同步返回給客户端?

简单问题: Nodejs http.get() 如何同步返回給客户端?

嗯嗯嗯,这应该是所有学习 node 的人必须过的一关:

  • 使用 http 内置模块,进行url 获取时
  • 因为 node 是异步的,从指定 url 下载数据,直到 end 事件发生时,才完成
  • 但是,作为一个 post 或是 get 请求过程中,就无法简单的,自然思路的返回数据了,

e.g::

app.post '/chk', (req, res) ->
    ...
    http.get options, (res) ->
        data = ''
        res.on 'data', (chunk) ->
            data += chunk.toString()
        res.on 'end', () ->
            answer = JSON.parse(data)
            console.log answer.success
    res.send answer
  • 这时,俺用 curl 什么的访问 127.0.0.1/chk ,給个网址
  • 那么,返回时,怎么也无法简单的获得 answer
  • 除了人工等待几秒,还有什么方案?

ps: 环境是:

  • node > v0.6.8
  • coffee v 1.2.0
  • express v2.5.8

17 回复

要解决这个问题,我们需要理解 Node.js 的异步特性。在 Node.js 中,处理 HTTP 请求通常需要异步操作来避免阻塞事件循环。因此,直接同步返回数据是不可能的。不过,我们可以使用一些方法来模拟同步行为。

示例代码

以下是一个使用 http.get 方法并将其结果同步返回给客户端的示例代码。这里我们使用了 async/await 来简化异步逻辑:

const express = require('express');
const http = require('http');

const app = express();

app.post('/chk', async (req, res) => {
    try {
        const options = {
            hostname: 'example.com',
            port: 80,
            path: '/somepath',
            method: 'GET'
        };

        let data = '';

        // 使用 promise 包装 http.get
        const response = await new Promise((resolve, reject) => {
            const req = http.get(options, (res) => {
                res.on('data', (chunk) => {
                    data += chunk;
                });
                res.on('end', () => {
                    resolve(data);
                });
            });

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

        // 解析响应数据
        const answer = JSON.parse(response);

        // 返回结果
        res.send(answer);
    } catch (error) {
        res.status(500).send({ error: 'Failed to fetch data' });
    }
});

app.listen(3000, () => {
    console.log('Server is running on port 3000');
});

解释

  1. 使用 async/await: 我们将 http.get 封装在一个 Promise 中,并使用 await 关键字来等待其完成。这样可以使得异步操作看起来像同步代码一样。

  2. 封装 http.get: 我们创建一个 Promise,在 http.get 完成后解析它。这样我们就可以在 await 中等待它完成。

  3. 错误处理: 使用 try/catch 块来捕获可能发生的错误,并适当地处理它们。

  4. 发送响应: 在 http.get 完成后,我们将解析的数据作为 JSON 发送给客户端。

这种方法虽然不是真正的同步执行,但通过 async/await 可以使代码更加简洁和易读。希望这能帮助你解决问题!


javascript - Node.js. Http.get() function is not responding. - Stack Overflow http://stackoverflow.com/questions/8893167/node-js-http-get-function-is-not-responding

javascript - Node.js: Parse JSON object - Stack Overflow http://stackoverflow.com/questions/6486208/node-js-parse-json-object

等等,都是从 console 返回給后台,然而前台要怎么办?

app.post '/chk', (req, res) ->
    ...
    http.get options, (gres) ->
        data = ''
        gres.on 'data', (chunk) ->
            data += chunk.toString()
        gres.on 'end', () ->
            answer = JSON.parse(data)
            console.log answer.success
            res.end answer

在 res.on 的 end 事件中,不论 res.write/send/end 都吼对象没有这个方法,

::

.../app.coffee:44
        return res.end(answer.success);
                   ^
TypeError: Object #<IncomingMessage> has no method 'end'
    at IncomingMessage.<anonymous> (/Users/zoomq/Works/@NAE/no.de/urisaok/app.coffee:44:20)
    at IncomingMessage.emit (events.js:88:20)
    at HTTPParser.onMessageComplete (http.js:137:23)
    at Socket.ondata (http.js:1147:24)
    at TCP.onread (net.js:354:27)

在 res.on 的 end 事件中,不论 res.write/send/end 都吼对象没有这个方法,

::

.../app.coffee:44
        return res.end(answer.success);
                   ^
TypeError: Object #<IncomingMessage> has no method 'end'
    at IncomingMessage.<anonymous> (/Users/zoomq/Works/@NAE/no.de/urisaok/app.coffee:44:20)
    at IncomingMessage.emit (events.js:88:20)
    at HTTPParser.onMessageComplete (http.js:137:23)
    at Socket.ondata (http.js:1147:24)
    at TCP.onread (net.js:354:27)

在 res.on 的 end 事件中,不论 res.write/send/end 都吼对象没有这个方法,

::

.../app.coffee:44
        return res.end(answer.success);
                   ^
TypeError: Object #<IncomingMessage> has no method 'end'
    at IncomingMessage.<anonymous> (/Users/zoomq/Works/@NAE/no.de/urisaok/app.coffee:44:20)
    at IncomingMessage.emit (events.js:88:20)
    at HTTPParser.onMessageComplete (http.js:137:23)
    at Socket.ondata (http.js:1147:24)
    at TCP.onread (net.js:354:27)

在 res.on 的 end 事件中,不论 res.write/send/end 都吼对象没有这个方法,

::

.../app.coffee:44
        return res.end(answer.success);
                   ^
TypeError: Object #<IncomingMessage> has no method 'end'
    at IncomingMessage.<anonymous> (/Users/zoomq/Works/@NAE/no.de/urisaok/app.coffee:44:20)
    at IncomingMessage.emit (events.js:88:20)
    at HTTPParser.onMessageComplete (http.js:137:23)
    at Socket.ondata (http.js:1147:24)
    at TCP.onread (net.js:354:27)

在 res.on 的 end 事件中,不论 res.write/send/end 都吼对象没有这个方法,

::

.../app.coffee:44
        return res.end(answer.success);
                   ^
TypeError: Object #<IncomingMessage> has no method 'end'
    at IncomingMessage.<anonymous> (/Users/zoomq/Works/@NAE/no.de/urisaok/app.coffee:44:20)
    at IncomingMessage.emit (events.js:88:20)
    at HTTPParser.onMessageComplete (http.js:137:23)
    at Socket.ondata (http.js:1147:24)
    at TCP.onread (net.js:354:27)

在 res.on 的 end 事件中,不论 res.write/send/end 都吼对象没有这个方法,

::

.../app.coffee:44
        return res.end(answer.success);
                   ^
TypeError: Object #<IncomingMessage> has no method 'end'
    at IncomingMessage.<anonymous> (/Users/zoomq/Works/@NAE/no.de/urisaok/app.coffee:44:20)
    at IncomingMessage.emit (events.js:88:20)
    at HTTPParser.onMessageComplete (http.js:137:23)
    at Socket.ondata (http.js:1147:24)
    at TCP.onread (net.js:354:27)

哈哈,pythonic都喜欢coffee

必然的,已经完全无法忍受无排版的代码以及多余的各种东西了,

嗯嗯嗯 ,最后用通用的流氓策略搞掂!

  • 找对应的模块 完成异步行为同步返回!

使用dependency injection,把获得的answer注入自定义callbalk中

//post function
function post(url, callback){
    app.post(url,function(req,res){
    ...
    res.on('end',function(){
        ...
        callback(answer);
    });
}

//good seperation
function sendAnswer(ans){
    res.end(ans);
}

//do the job
post('/chk',sendAnswer);

看看有没有什么帮助http://www.9958.pw/post/nodejs_get_html_a

npm install -g xd-synchttp

安装完成后,示例代码如下。

const sync = require('xd-synchttp');
let content = "";
try{
    content = sync.http_get('http://www.csdn.net',0);//0为不超时,其他数值为超时秒数
}
catch(err){
console.log(err);
}

对于这个问题,由于 Node.js 的异步特性,直接同步地返回 http.get 的结果是不可能的。你需要处理异步逻辑,让请求的结果在准备好后返回给客户端。

可以使用 Promise 或 async/await 来管理异步操作,使得代码看起来更像同步代码。这里提供一个使用 async/await 的例子:

const express = require('express');
const http = require('http');
const app = express();

app.post('/chk', async (req, res) => {
    const options = { /* your options here */ };
    
    try {
        const result = await new Promise((resolve, reject) => {
            const req = http.get(options, response => {
                let data = '';
                response.on('data', chunk => data += chunk);
                response.on('end', () => resolve(data));
            });
            req.on('error', reject);
        });

        const answer = JSON.parse(result);
        console.log(answer.success);
        res.send(answer);
    } catch (error) {
        console.error(error);
        res.status(500).send({ error: "Failed to fetch data" });
    }
});

app.listen(3000, () => console.log('Server running on port 3000'));

上述代码中,我们创建了一个返回 Promise 的函数来处理 http.get 请求,并使用 await 等待其完成。这样就可以在 Express 的路由处理函数中以同步方式编写异步代码。这样做的好处是代码更加清晰,逻辑更容易理解。

回到顶部