在我的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
中引用的静态资源时,请求最终会挂起并超时并产生“没有收到数据”。我做错了什么?
答案 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);
});
我希望你能找到有用的例子。