Node.js HTTP代理修改主体

时间:2014-03-18 17:44:34

标签: javascript node.js http proxy node-http-proxy

我想编程Node.js http代理,它将能够修改响应体。到目前为止我已经这样做了:

http = require('http'),
httpProxy = require('http-proxy');

var proxy = httpProxy.createProxyServer();
http.createServer( function (req, res){
    //here I want to change the body I guess
    proxy.web(req, res, {
        target: req.url
    });
}).listen(8013);

我曾尝试使用res.write(),但它给出了一个错误“无法在发送后设置标头”。好吧,我不想改变标题,我想改变身体 我该如何改变身体?任何建议将不胜感激。

2 个答案:

答案 0 :(得分:5)

您收到该错误,因为写入HTTP响应必然会更改标头; Content-Length必须正确。

我解决这个问题的方法是缓冲整个响应主体,使用cheerio来解析和调整,然后将结果发送给客户端。

我通过猴子修补res.writeHeadres.writeres.end来完成此操作,然后将请求交给http代理模块。

function requestHandler(req, res) {
    var writeHead = res.writeHead, write = res.write, end = res.end;

    res.writeHead = function(status, reason, headers) {
        if (res.headersSent) return req.socket.destroy(); // something went wrong; abort
        if (typeof reason == 'object') headers = reason;
        headers = headers || {};
        res.headers = headers;
        if (headers['content-type'] && headers['content-type'].substr(0,9) == 'text/html') { // we should only fiddle with HTML responses
            delete headers['transfer-encoding']; // since we buffer the entire response, we'll send a proper Content-Length later with no Transfer-Encoding.

            var buf = new Buffer();
            res.write = function(data, encoding) {
                if (Buffer.isBuffer(data)) buf = Buffer.concat([buf, data]); // append raw buffer
                else buf = Buffer.concat([buf, new Buffer(data, encoding)]); // append string with optional character encoding (default utf8)

                if (buf.length > 10 * 1024 * 1024) error('Document too large'); // sanity check: if the response is huge, bail.
                // ...we don't want to let someone bring down the server by filling up all our RAM.
            }

            res.end = function(data, encoding) {
                if (data) res.write(data, encoding);

                var $ = cheerio.load(buf.toString());

                // This is where we can modify the response.  For example,
                $('body').append('<p>Hi mom!</p>');

                buf = new Buffer($.html()); // we have to convert back to a buffer so that we can get the *byte count* (rather than character count) of the body

                res.headers['content-type'] = 'text/html; charset=utf-8'; // JS always deals in UTF-8.
                res.headers['content-length'] = buf.length;

                // Finally, send the modified response out using the real `writeHead`/`end`:
                writeHead.call(res, status, res.headers);
                end.call(res, buf);
            }


        } else {
            writeHead.call(res, status, headers); // if it's not HTML, let the response go through normally
        }
    }

    proxy.web(req, res, {
        target: req.url
    });

    function error(msg) { // utility function to report errors
        if (res.headersSent) end.call(res, msg);
        else {
            msg = new Buffer(msg);
            writeHead.call(res, 502, { 'Content-Type': 'text/plain', 'Content-Length': msg.length });
            end.call(res, msg);
        }
    }
}

答案 1 :(得分:1)