javascript - Node.js 响应异步数据

标签 javascript node.js asynchronous proxy callback

最近我开始学习一些关于 Node.js 及其功能的知识,并尝试将其用于某些 Web 服务。 我想创建一个 Web 服务,作为 Web 请求的代理。 我希望我的服务以这种方式工作:

  1. 用户将访问我的服务 -> http://myproxyservice.com/api/getuserinfo/tom
  2. 我的服务将执行请求 -> http://targetsite.com/user?name=tom
  3. 响应的数据将反射(reflect)给用户。

为了实现它,我使用了以下代码:

应用程序.js:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();

app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

var proxy = require('./proxy_query.js')

function makeProxyApiRequest(name) {
  return proxy.getUserData(name, parseProxyApiRequest);
}

function parseProxyApiRequest(data) {
  returned_data = JSON.parse(data);
  if (returned_data.error) {
    console.log('An eror has occoured. details: ' + JSON.stringify(returned_data));
    returned_data = '';
  }
  return JSON.stringify(returned_data);
}

app.post('/api/getuserinfo/tom', function(request, response) {
  makeProxyApiRequest('tom', response);
  //response.end(result);
});

var port = 7331;

proxy_query.js:

var https = require('https');

var callback = undefined;

var options = {
    host: 'targetsite.com',
    port: 443,
    method: 'GET',
};

function resultHandlerCallback(result) {
    var buffer = '';

    result.setEncoding('utf8');
    result.on('data', function(chunk){
        buffer += chunk;
    });

    result.on('end', function(){
        if (callback) {
            callback(buffer);
        }
    });
}

exports.getUserData = function(name, user_callback) {
    callback = user_callback
    options['path'] = user + '?name=' + name;

    var request = https.get(options, resultHandlerCallback);

    request.on('error', function(e){
        console.log('error from proxy_query:getUserData: ' + e.message)
    });

    request.end();
}
app.listen(port);

我希望我没有搞砸这段代码,因为我替换了一些东西以适合我的示例。

无论如何,问题是我想在 HTTP 请求完成后将响应发布给用户,但我找不到如何这样做,因为我使用 express,而 express 使用异步调用,http 请求也是如此。 我知道如果我想这样做,我应该将响应对象传递给 makeProxyApiRequest,这样他就可以将它传递给回调,但由于异步问题,这是不可能的。

有什么建议吗? 帮助将不胜感激。

最佳答案

当您在路由处理中使用您的函数来处理请求时,最好将它们编写为 express 中间件函数,采用特定的请求/响应对,并利用 express 的 next 级联型号:

function makeProxyApiRequest(req, res, next) {
  var name = parseProxyApiRequest(req.name);
  res.locals.userdata = proxy.getUserData(name);
  next();
}

function parseProxyApiRequest(req, res, next) {
  try {
    // remember that JSON.parse will throw if it fails!
    data = JSON.parse(res.locals.userdata);
    if (data .error) {
      next('An eror has occoured. details: ' + JSON.stringify(data));
    }
    res.locals.proxyData = data;
    next();
  }
  catch (e) { next("could not parse user data JSON.");  }
}

app.post('/api/getuserinfo/tom',
  makeProxyApiRequest,
  parseProxyApiRequest,
  function(req, res) {
    // res.write or res.json or res.render or
    // something, with this specific request's
    // data that we stored in res.locals.proxyData
  }
);

更好的做法是现在将这些中间件函数移动到它们自己的文件中,这样您就可以简单地执行以下操作:

var middleware = require("./lib/proxy_middleware");
app.post('/api/getuserinfo/tom',
  middleware.makeProxyApiRequest,
  middleware.parseProxyApiRequest,
  function(req, res) {
    // res.write or res.json or res.render or
    // something, with this specific request's
    // data that we stored in res.locals.proxyData
  }
);

并使您的 app.js 尽可能小。请注意,客户端的浏览器将简单地等待 express 的响应,这会发生一次 res.writeres.jsonres.render 等用来。在此之前,浏览器和服务器之间的连接只是保持打开状态,所以如果您的中间件调用需要很长时间,那也没关系 - 浏览器会很乐意地等待很长的时间来返回响应,同时会做其他事情。

现在,为了得到 name,我们可以使用 express 的参数构造:

app.param("name", function(req, res, next, value) {
  req.params.name = value;
  // do something if we need to here, like verify it's a legal name, etc.
  // for instance:
  var isvalidname = validator.checkValidName(name);
  if(!isvalidname) { return next("Username not valid"); }
  next(); 
});

...

app.post("/api/getuserinfo/:name", ..., ..., ...);

使用此系统,将根据我们使用 app.param 定义的 name 参数处理任何路由的 :name 部分。请注意,我们不需要多次定义它:我们可以执行以下操作,它就会正常工作:

app.post("/api/getuserinfo/:name", ..., ..., ...);
app.post("/register/:name", ..., ..., ... );
app.get("/api/account/:name", ..., ..., ... );

对于每个带有 :name 的路由,“name”参数处理程序的代码将启动。

至于 proxy_query.js 文件,将其重写为适当的模块可能比使用单独的导出更安全:

// let's not do more work than we need: http://npmjs.org/package/request
// is way easier than rolling our own URL fetcher. In Node.js the idea is
// to write as little as possible, relying on npmjs.org to find you all
// the components that you need to glue together. If you're writing more
// than just the glue, you're *probably* doing more than you need to.
var request = require("request");
module.exports = {
  getURL: function(name, url, callback) {
   request.get(url, function(err, result) {
     if(err) return callback(err);
     // do whatever processing you need to do to result:
     var processedResult = ....
     callback(false, processedResult);
   });
  }
};

然后我们可以将其用作 proxy = require("./lib/proxy_query"); 在中间件中我们需要实际执行 URL 数据获取。

关于javascript - Node.js 响应异步数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27081949/

相关文章:

javascript - 记录复杂对象时内存泄漏

javascript - 这个 javascript es6 胖箭头函数的 db 参数的值或用法是什么?

javascript - 让所有功能异步的任何缺点?

javascript - 通俗地理解异步代码

javascript - 保持 Bootstrap 日期选择器始终打开

javascript - 如何提取 JavaScript native 异常的所有信息?

javascript - 搜索字符串但忽略标签

javascript - 如何路由到 sails.js 中的函数

javascript - 在 JavaScript Discord Bot 中,为什么 message.react() 是 "not a function"

python - 如何在 Python 中使用 `async for`?