节点 JS HTTP 代理挂起

Node JS HTTP Proxy hanging up

我有一个 http-proxy 来代理任何网站,并在将 HTML 服务回客户端之前注入一些自定义 JS 文件。每当我尝试访问代理网站时,它都会挂断或浏览器似乎不确定加载。但是当我检查 HTML 源时,我成功地注入了我的自定义 JavaScript 文件。这是代码:

const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');

_initProxy(host: string) {
    let proxy = httpProxy.createProxyServer({});
    let option = {
        target: host,
        selfHandleResponse: true
    };

    proxy.on('proxyRes', function (proxyRes, req, res) {
        let body = [];
        proxyRes.on('data', function (chunk) {
            body.push(chunk);
        });
        proxyRes.on('end', async function () {
            let buffer = Buffer.concat(body);
            if (proxyRes.headers['content-encoding'] === 'gzip') {
                try {
                    let $ = null;
                    const decompressed = await ungzip(buffer);
                    const scriptTag = '<script src="my-customjs.js"></script>';
                    $ = await cheerio.load(decompressed.toString());
                    await $('body').append(scriptTag);
                    res.end($.html());
                } catch (e) {
                    console.log(e);
                }
            }
        });
    });

    let server = http.createServer(function (req, res) {
        proxy.web(req, res, option, function (e) {
            console.log(e);
        });
    });

    console.log("listening on port 5051");
    server.listen(5051);
}

如果我做错了什么,有人能告诉我吗,node-http-proxy 似乎快要死了,不能太依赖它,因为代理有时可以工作,然后在下一次死掉 运行,取决于我运行服务器的次数。

你的代码看起来不错,所以我很好奇并试了一下。

尽管您确实记录了一些错误,但您没有处理以下几种情况:

  • 服务器 returns 一个 body 没有响应(cheerio 将在这种情况下生成一个空的 HTML body)
  • 服务器 return 未压缩的响应(您的代码将自动丢弃响应)

我对你的代码做了一些修改。

更改初始选项

let proxy = httpProxy.createProxyServer({
    secure: false,
    changeOrigin: true
});
  • 不验证 TLS 证书secure: false
  • 发送正确的HostheaderchangeOrigin: true

删除if语句并用三元替换它

const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
const decompressed = isCompressed ? await ungzip(buffer) : buffer;

您还可以删除 cheerio 上的 2 await,Cheerio 不是异步的,return 也不能 await

最终代码

这是有效的最终代码。你提到 "it looks like node-http-proxy is dying a lot [...] depending on how many times I ran the server." 我没有遇到过这样的稳定​​性问题,所以如果发生这种情况,你的问题可能出在其他地方(坏 ram?)

const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');

const host = 'https://github.com';

let proxy = httpProxy.createProxyServer({
    secure: false,
    changeOrigin: true
});
let option = {
    target: host,
    selfHandleResponse: true
};

proxy.on('proxyRes', function (proxyRes, req, res) {

    console.log(`Proxy response with status code: ${proxyRes.statusCode} to url ${req.url}`);
    if (proxyRes.statusCode == 301) {
        throw new Error('You should probably do something here, I think there may be an httpProxy option to handle redirects');
    }
    let body = [];
    proxyRes.on('data', function (chunk) {
        body.push(chunk);
    });
    proxyRes.on('end', async function () {
        let buffer = Buffer.concat(body);
        try {
            let $ = null;
            const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
            const decompressed = isCompressed ? await ungzip(buffer) : buffer;
            const scriptTag = '<script src="my-customjs.js"></script>';
            $ = cheerio.load(decompressed.toString());
            $('body').append(scriptTag);
            res.end($.html());
        } catch (e) {
            console.log(e);
        }
    });
});

let server = http.createServer(function (req, res) {
    proxy.web(req, res, option, function (e) {
        console.log(e);
    });
});

console.log("listening on port 5051");
server.listen(5051);

我最终使用 CherryPy 编写了一个小型 Python 服务器,并使用 mitmproxy 代理了网络应用程序。现在一切都很顺利。也许我在使用 node-http-proxy 时做错了,但我也对在生产环境中使用它持怀疑态度。