如何在反向代理响应中打开正文标签后插入一个片段
How do I inject a snippet after the opening body tag in a reverse-proxied response
我从上游得到一个 HTML 页面,格式如下:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
...
</head>
<body class="foo bar baz" data-foo="klaskassa" data-baz="lkaslkas" id="body">
...
</body>
</html>
我有一个 HTML 形式的片段:
<div class="my-snippet">
...
</div>
我想在开始 body
标签后插入代码段,给我:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
...
</head>
<body class="foo bar baz" data-foo="klaskassa" data-baz="lkaslkas" id="body">
<div class="my-snippet">
...
</div>
...
</body>
</html>
限制
解决方案必须修改流,而不是在 运行 转换之前将正文收集到单个字符串中。此应用受内存限制,处理的请求太多,无法承受这种性能损失。
我尝试过的事情
- Harmon:显然你不能读写元素的内部。参见 this, this, and this。
- 使用
replacestream
概述 here 但这没有用,事实上我的反应刚刚停止。
- Transformer-proxy: 但是
data
对象只能附加到.
- 在 Ruby 中花了 4 个小时写了一个 Rack 应用程序,但后来我醒悟过来并停止重写我的整个代码库。
请:
在答案中添加示例代码。由于这基本上是一个 connect
应用程序,我可以插入你给我的任何中间件。
所以我创建了一个简单的服务器来启动代理服务器和普通服务器
var http = require('http'),
httpProxy = require('http-proxy');
proxy = httpProxy.createProxyServer({
target:'http://localhost:9000',
}).listen(8000);
//
// Create your target server
//
http.createServer(function (req, res) {
let data = 'request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2);
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': data.length });
res.write(data);
res.end();
}).listen(9000);
然后使用下面的方法进行相同的测试
$ curl "localhost:8000"
request successfully proxied!
{
"accept": "*/*",
"user-agent": "curl/7.54.0",
"host": "localhost:8000",
"connection": "close"
}
然后在下面找到的文档中
selfHandleResponse true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event
所以像下面这样更新代码
var http = require('http'),
httpProxy = require('http-proxy');
proxy = httpProxy.createProxyServer({
target:'http://localhost:9000',
selfHandleResponse: true
}).listen(8000); // See (†)
proxy.on('proxyRes', function(proxyRes, req, res) {
if (proxyRes.headers["content-type"] && proxyRes.headers["content-type"].indexOf("text/plain") >=0) {
// We need to do our modification
if (proxyRes.headers["content-length"]) {
//need to remove this header as we may modify the response
delete proxyRes.headers["content-length"];
}
var responseModified = false;
proxyRes.on('data', (data) => {
let dataStr = "";
if (!responseModified && (dataStr = data.toString()) && dataStr.indexOf("proxied!") >= 0) {
responseModified = true;
dataStr = dataStr.replace("proxied!", "proxied? Are you sure?")
res.write(Buffer.from(dataStr, "utf8"));
console.log("Writing modified data");
} else {
res.write(data);
console.log("Writing unmodified data");
}
});
proxyRes.on('end', (data) => {
console.log("data ended")
res.end();
});
} else {
proxyRes.pipe(res)
}
});
//
// Create your target server
//
http.createServer(function (req, res) {
let data = 'request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2);
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': data.length });
res.write(data);
res.end();
}).listen(9000);
再次测试
$ curl "localhost:8000"
request successfully proxied? Are you sure?
{
"accept": "*/*",
"user-agent": "curl/7.54.0",
"host": "localhost:8000",
"connection": "close"
}
现在服务器控制台上的输出如下
Writing modified data
data ended
这并不能确认我们是否真的只修改了部分流。所以我改变了下面的代码
http.createServer(function (req, res) {
let data = 'request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2);
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': data.length * 5});
res.write(data + data)
setTimeout(() => {
res.write(data + data + data);
res.end();
});
}).listen(9000);
并在浏览器中打开
如您所见,数据在流中被替换,并且根据逻辑,替换只发生一次,流的其余部分按原样传递
我从上游得到一个 HTML 页面,格式如下:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
...
</head>
<body class="foo bar baz" data-foo="klaskassa" data-baz="lkaslkas" id="body">
...
</body>
</html>
我有一个 HTML 形式的片段:
<div class="my-snippet">
...
</div>
我想在开始 body
标签后插入代码段,给我:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
...
</head>
<body class="foo bar baz" data-foo="klaskassa" data-baz="lkaslkas" id="body">
<div class="my-snippet">
...
</div>
...
</body>
</html>
限制
解决方案必须修改流,而不是在 运行 转换之前将正文收集到单个字符串中。此应用受内存限制,处理的请求太多,无法承受这种性能损失。
我尝试过的事情
- Harmon:显然你不能读写元素的内部。参见 this, this, and this。
- 使用
replacestream
概述 here 但这没有用,事实上我的反应刚刚停止。 - Transformer-proxy: 但是
data
对象只能附加到. - 在 Ruby 中花了 4 个小时写了一个 Rack 应用程序,但后来我醒悟过来并停止重写我的整个代码库。
请:
在答案中添加示例代码。由于这基本上是一个 connect
应用程序,我可以插入你给我的任何中间件。
所以我创建了一个简单的服务器来启动代理服务器和普通服务器
var http = require('http'),
httpProxy = require('http-proxy');
proxy = httpProxy.createProxyServer({
target:'http://localhost:9000',
}).listen(8000);
//
// Create your target server
//
http.createServer(function (req, res) {
let data = 'request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2);
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': data.length });
res.write(data);
res.end();
}).listen(9000);
然后使用下面的方法进行相同的测试
$ curl "localhost:8000"
request successfully proxied!
{
"accept": "*/*",
"user-agent": "curl/7.54.0",
"host": "localhost:8000",
"connection": "close"
}
然后在下面找到的文档中
selfHandleResponse true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event
所以像下面这样更新代码
var http = require('http'),
httpProxy = require('http-proxy');
proxy = httpProxy.createProxyServer({
target:'http://localhost:9000',
selfHandleResponse: true
}).listen(8000); // See (†)
proxy.on('proxyRes', function(proxyRes, req, res) {
if (proxyRes.headers["content-type"] && proxyRes.headers["content-type"].indexOf("text/plain") >=0) {
// We need to do our modification
if (proxyRes.headers["content-length"]) {
//need to remove this header as we may modify the response
delete proxyRes.headers["content-length"];
}
var responseModified = false;
proxyRes.on('data', (data) => {
let dataStr = "";
if (!responseModified && (dataStr = data.toString()) && dataStr.indexOf("proxied!") >= 0) {
responseModified = true;
dataStr = dataStr.replace("proxied!", "proxied? Are you sure?")
res.write(Buffer.from(dataStr, "utf8"));
console.log("Writing modified data");
} else {
res.write(data);
console.log("Writing unmodified data");
}
});
proxyRes.on('end', (data) => {
console.log("data ended")
res.end();
});
} else {
proxyRes.pipe(res)
}
});
//
// Create your target server
//
http.createServer(function (req, res) {
let data = 'request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2);
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': data.length });
res.write(data);
res.end();
}).listen(9000);
再次测试
$ curl "localhost:8000"
request successfully proxied? Are you sure?
{
"accept": "*/*",
"user-agent": "curl/7.54.0",
"host": "localhost:8000",
"connection": "close"
}
现在服务器控制台上的输出如下
Writing modified data
data ended
这并不能确认我们是否真的只修改了部分流。所以我改变了下面的代码
http.createServer(function (req, res) {
let data = 'request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2);
res.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': data.length * 5});
res.write(data + data)
setTimeout(() => {
res.write(data + data + data);
res.end();
});
}).listen(9000);
并在浏览器中打开
如您所见,数据在流中被替换,并且根据逻辑,替换只发生一次,流的其余部分按原样传递