Node.js 静态 Assets 代理

标签 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 中引用的静态资源时,请求就会挂起,最终超时并产生“未收到数据”的结果。我做错了什么?

最佳答案

我可以通过以下行看到问题:

proxyRes.pipe(res);

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

最简单的解决方案是发回“请求”已保存的正文:

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

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

为了使其能够使用二进制资源,您需要缓冲来自代理的响应,从代理发出请求开始。最终,根据响应,您可能决定将其流回浏览器。您还需要传递 header ,以便浏览器获取如何正确解码二进制正文内容的信息。

// 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);
});

我希望您发现该示例有用。

关于Node.js 静态 Assets 代理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23414309/

相关文章:

node.js - 使用 IISNode 在 IIS 中托管 Nodejs 应用程序时如何启用静态文件(和较少的支持)

node.js - nodejs exec 让 shell 保持事件状态?

javascript - 无法读取未定义的属性 'push'

javascript - 为什么我的中间件执行了两次?

node.js - 测试 socket.io 事件

javascript - 为什么要在服务器上构建 MEAN 应用程序?

node.js - Express cookieSession 不填充 req.session

node.js - 如何从响应正文中检索参数

node.js - TypeScript 在 Express 中添加自定义请求 header

javascript - 404 错误 快速路线