5

応答本文を変更できる 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()たが、「送信後にヘッダーを設定できません」というエラーが表示されます。ヘッダーを変更したくないのですが、本文を変更したいのです。
どうやって体を変えるの?任意の提案をいただければ幸いです。

4

2 に答える 2

5

HTTP 応答に書き込むと必ずヘッダーが変更されるため、このエラーが発生します。はContent-Length正しくなければなりません。

この問題に対する私のアプローチは、応答本文全体をバッファリングし、cheerioを使用して解析および調整し、結果をクライアントに送信することでした。

これは、リクエストを http-proxy モジュールに渡す前にres.writeHead、 、res.write、およびにモンキー パッチを適用することで実現しました。res.end

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);
        }
    }
}
于 2014-03-18T18:25:48.190 に答える
1

http-proxy モジュールの git リポジトリからこのサンプルを確認してください

https://github.com/nodejitsu/node-http-proxy/blob/master/examples/middleware/modifyResponse-middleware.js

于 2014-03-18T18:30:52.073 に答える