Дамп всей HTTP-связи как необработанные данные в nodejs - PullRequest
0 голосов
/ 04 июня 2018

Интересно, возможно ли сбросить весь HTTP-запрос + ответ, когда он идет по проводам.

Я не хочу получать метод, информацию о пути, строку запроса, заголовки,печенье, тело и все такое.Теоретически я мог бы собрать исходные данные сам, но тогда мне не понадобилась бы библиотека HTTP, верно?

Более того, я хочу вывести именно те байты, которые проходят по проводам .

Мне нужны необработанные данные, как на этом изображении

http raw data

взято с этой страницы .

Я использую текущий node.js в качестве HTTP клиента с request.Это простой HTTP (без HTTPS).

Установка прокси в node.js возможна, но я не настаиваю на библиотеке.Я мог бы представить, как обернуть функции чтения и записи в сокет, но не понимаю, как добраться до используемого сокета.

Ответы [ 3 ]

0 голосов
/ 13 июня 2018

Модуль запроса возвращает дополненные нативные объекты.Возвращаемым значением является расширенный http.ClientRequest объект (вид), а обратный вызов предоставляется расширенным http.IncomingMessage в качестве второго аргумента.Вы можете использовать различные свойства для восстановления ответа, но вы не можете получить его напрямую отсюда.Собственный http API, который предоставляет Node, абстрагирует от необработанного ответа.

(Документы для IncomingMessage и ClientRequest здесь: https://nodejs.org/api/http.html).

Что еще интереснее, это обе абстракции над net.Socket. Если вы используете собственный http API,Вы можете прослушать этот Socket перед отправкой ClientRequest.end). Это даст вам Buffer, содержащий ответ HTTP.

let http = require("http");
let nativeRequest = http.get({
    host: "google.com"
}); //get a ClientRequest object
nativeRequest.on('socket', function (socket) {
    socket.on('data', function (data) { console.log(data.toString()); });
});
nativeRequest.end();

Это не похоже наэто позволяет вам отслеживать исходящий запрос, но отлично работает для ответа.

Возвращаясь вверх по цепочке абстракций, это прекрасно работает с запросом. Я пропущу фрагмент, потому что он почти идентичен обоимпредыдущий и последующий.

Чтобы получить запрос, мы можем покопаться во внутренних элементах сокета, чтобы узнать, не можем ли мы чем-то злоупотребить. Object.keys(socket) возвращает следующий массив:

[
   "connecting",
   "_hadError",
   "_handle",
   "_parent",
   "_host",
   "_readableState",
   "readable",
   "domain",
   "_events",
   "_eventsCount",
   "_maxListeners",
   "_writableState",
   "writable",
   "allowHalfOpen",
   "destroyed",
   "_bytesDispatched",
   "_sockname",
   "_pendingData",
   "_pendingEncoding",
   "server",
   "_server",
   "parser",
   "_httpMessage"
]

И, действительно, если мы посмотрим на подозрительно выглядящий _pendingData, мы сможем просмотреть запрос до его отправки:

let request = require('request');

let req = request("http://google.com", function (e, r, d) {});
req.on('socket', function (socket) {
    console.log("========\nRequest\n========")
    console.log(JSON.stringify(socket._pendingData, null, 3));
    console.log("========\nResponse\n========");
    socket.on('data', function (data) { console.log(data.toString()); });
});
0 голосов
/ 13 июня 2018

http.request также имеет возможность передать ваше собственное соединение (createConnection).Вы можете использовать эту опцию, чтобы предоставить свое собственное созданное соединение, которое "piped ()" для потока преобразования логгера.

const { Transform } = require('stream');
const http = require('http');
const agent = new http.Agent();
let nativeRequest = http.get({
    host: 'google.com',
    createConnection: options => {
        let connection = agent.createConnection(options);
        let logger = new Transform({
            transform: (chunk, encoding, callback) => {
                console.log(chunk.toString());
                connection.write(chunk, encoding, callback);
            },
            flush: () => {},
        });
        connection.pipe(logger);
        return logger;
    },
});
nativeRequest.on('socket', function(socket) {
    socket.on('data', function(data) {
        console.log(data.toString());
    });
});
nativeRequest.end();

Некоторые заметки

Я попытался реализовать поток PassThrough вместо Transform.Это дало мне ошибку разбора HTTP, когда я передал поток PassThrough к соединению.Я не знаю, почему, если честно.

Важно включить flush: () => {}, из документации

Это будет вызвано, когда больше нет письменных данных, которые нужнопотребляется, но до того, как передается событие «end», сигнализирующее об окончании считываемого потока.

https://nodejs.org/api/stream.html#stream_transform_flush_callback

0 голосов
/ 10 июня 2018

Это вернет заголовки запроса, отправленные как ответ

 const http = require("http")

function getRawHeader(req, res) {
    const httpVersion = req.httpVersion
    let str = `${req.method.toUpperCase()} ${req.url} HTTP/${httpVersion}\n`
    for (let i = 0; i < req.rawHeaders.length; i = i + 2) {
        str += `${req.rawHeaders[1]}  : ${req.rawHeaders[i + 1]}\n`
        console.log(i)
    }
    let written = false
    req.on("readable", (chunk) => {
        const data = req.read()
        if (!written) {
            res.write(str)
            res.write("\n")
        }
        written = true
        if (data) res.write(data)
    })

}

http.createServer((req, res) => {
    getRawHeader(req, res)
    req.on("end", () =>res.end())
}).listen(7200, () => console.log("server f is running"))
...