node.js静态资产代理

时间:2014-05-01 18:44:28

标签: node.js express

在我的Express应用程序中,我有一个如下定义的路径:

// catch-all for static assets used by the UI
app.get('*', require('./lib/routes/static'));

我想将静态文件的请求代理到在别处运行的网络服务器。为此我写了这篇中间件:

// static.js
var request = require('request');

// static assets are served through another webserver to which we proxy
module.exports = function(req, res, next) {
  var host = process.env.UI_URL;
  var url = req.url;

  request(host + url, function(err, proxyRes) {
    if (err) {
      next(err);
    }
    // if the resource is a 404, serve `index.html` served by the `host` to enable using the `pushState` API in the browser
    if (proxyRes.statusCode === 404) {
      request(host).pipe(res);
    }
    // if the resource is not a 404, pipe the proxy response into the response to the original request
    else {
      proxyRes.pipe(res);
    }
  });
};

当我点击/asd/asd这样的虚假网址时,该应用获取index.html文件没问题。因此404的逻辑分支按预期工作。但是当浏览器试图获取index.html中引用的静态资源时,请求最终会挂起并超时并产生“没有收到数据”。我做错了什么?

1 个答案:

答案 0 :(得分:1)

我可以看到行的问题:

proxyRes.pipe(res);

到时间节点将到达该行,整个响应流将已经完成。显然请求'模块在调用处理函数之前等待整个流。否则他们将无法通过正文传递第三个参数。

最简单的解决方案是通过'请求发送已经保存的正文:

 request(host + url, function(err, proxyRes, body) {
   ...
   else {
     res.send(body);
   }
 }

,但这不适用于图像和其他二进制内容,因为正文已被解码为字符串。

要使其与二进制资源一起使用,您需要从代理缓冲响应,从代理请求开始。然后最终,根据响应,您可能决定将其流回浏览器。您还需要传递标题,以便浏览器获取有关如何正确解码二进制正文内容的信息。

// static.js
var request = require('request'),
    stream = require('stream'),
    util = require('util');

function Buffer() {
  var pumping = true,
      queue = [],
      push = this.push.bind(this);

  function flush() {
    if (!pumping) return;
    while (queue.length && (pumping = push.apply({}, queue.shift())));
  }
  this._read = function () {
    pumping = true;
    flush();
  };
  this._write = function (chunk, encoding, callback) {
    queue.push([chunk, encoding]);
    callback();
  };
  stream.Duplex.call(this);
}
util.inherits(Buffer, stream.Duplex);

app.get('*', function(req, res, next) {
    var host = process.env.UI_URL,
        url = req.url,
        buffer = new Buffer();

  request(host + url, function(err, proxyRes, body) {
    if (err) {
      next(err);
    }
    if (proxyRes.statusCode === 404) {
      request(host).pipe(res);
    }
    else {
      res.set(proxyRes.headers);
      buffer.pipe(res);
    }
  }).pipe(buffer);
});

我希望你能找到有用的例子。