Node JS HTTP прокси зависает - PullRequest
7 голосов
/ 17 марта 2020

У меня есть http-прокси для прокси любого веб-сайта и добавления какого-либо пользовательского файла JS перед тем, как отправить HTML клиенту. Всякий раз, когда я пытаюсь получить доступ к прокси-сайту, он зависает или браузер загружается неопределенно. Но когда я проверял источник 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 много умирает и не может на него положиться, так как прокси может работать иногда и d ie при следующем запуске, в зависимости от того, сколько раз я запускал сервер.

Ответы [ 2 ]

3 голосов
/ 21 марта 2020

Ваш код выглядел нормально, поэтому мне было любопытно и попробовал его.

Хотя вы регистрируете несколько ошибок, вы не обрабатываете несколько случаев:

  • Сервер возвращает тело без ответа (cheerio сгенерирует пустое HTML тело, когда это происходит)
  • Сервер возвращает ответ, который не был распакован (ваш код будет молча отбрасывать ответ)

Я внес несколько изменений в ваш код.

Изменить начальные параметры

let proxy = httpProxy.createProxyServer({
    secure: false,
    changeOrigin: true
});
  • Не проверять сертификаты TLS secure: false
  • Отправить правильный заголовок Host changeOrigin: true

Удалите оператор if и замените его троичным

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

Вы также можете удалить 2 await на cheerio, Cheerio не asyn c и не возвращает await возможность.

Финальный код

Вот финальный код, который работает. Вы упомянули, что «похоже, что узел-http-прокси сильно умирает [...] в зависимости от того, сколько раз я запускал сервер». У меня не было таких проблем со стабильностью, поэтому ваши проблемы могут быть ie в другом месте, если это происходит (плохой баран?)

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);
0 голосов
/ 27 марта 2020

В итоге я написал небольшой Python Сервер с использованием CherryPy и проксировал веб-приложение с помощью mitmproxy. Теперь все работает без сбоев. Может быть, я неправильно делал с node-http-proxy, но я также стал скептичен c по поводу его использования в производственной среде.

...