[英]node.js static assets proxy
在我的Express应用中,我定义了这样一条路线:
// catch-all for static assets used by the UI
app.get('*', require('./lib/routes/static'));
我想将对静态文件的请求代理到其他地方运行的Web服务器。 为此,我编写了这段中间件:
// 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
这样的虚假url时,应用程序毫无问题地获取了index.html
文件。 因此404
的逻辑分支按预期工作。 但是,当浏览器试图获取index.html
引用的静态资源时,该请求最终将挂起,最终超时并产生“未接收到数据”。 我究竟做错了什么?
我可以看到以下问题:
proxyRes.pipe(res);
到节点到达该行的时间,整个响应流将已经完成。 显然,“请求”模块在调用处理程序函数之前会等待整个流。 否则,他们将无法通过body传递第三个参数。
最简单的解决方案是将已经通过“请求”保存的正文发送回去:
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);
});
我希望您觉得这个例子有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.