Je me demande s'il est possible de vider la totalité de la requête + réponse HTTP au fur et à mesure qu'elle passe par le fil.
Je ne veux pas obtenir la méthode, les informations sur le chemin, la chaîne de requête, les en-têtes, les cookies, le corps et autres. Je pourrais en théorie assembler les données brutes moi-même, mais je n'aurais alors pas besoin de bibliothèque HTTP, non?
De plus, je veux vider exactement les octets qui passent sur le fil .
Je veux les données brutes comme dans cette image
tiré de cette page .
J'utilise le courant node.js
en tant que client HTTP avec request
. C'est du HTTP simple (pas de HTTPS).
Installer un proxy dans node.js serait une option, mais je n'insiste pas sur une bibliothèque. Je pourrais imaginer encapsuler les fonctions de lecture et d'écriture du socket, mais je ne vois pas comment accéder au socket utilisé.
Le module Request renvoie des objets natifs augmentés. La valeur de retour est un objet http.ClientRequest
Augmenté (sorte de), et le rappel est fourni un http.IncomingMessage
Augmenté comme deuxième argument. Vous pouvez utiliser les différentes propriétés pour reconstruire la réponse, mais vous ne pouvez pas l'obtenir directement à partir d'ici. L'API http native qui Node fournit des résumés loin de la réponse brute.
(Les documents pour IncomingMessage
et ClientRequest
sont ici: https://nodejs.org/api/http.html ).
Plus intéressant, ce sont deux abstractions sur net.Socket
. Si vous utilisez l'API native http
, vous pouvez l'écouter Socket
avant d'envoyer un ClientRequest
(avec .end
). Cela vous donnera un Buffer
contenant la réponse 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();
Il ne semble pas que cela vous permet d'espionner la demande sortante, mais cela fonctionne très bien pour la réponse.
En remontant la chaîne d'abstraction, cela fonctionne très bien avec Request. Je vais sauter l'extrait de code, car il est presque identique à la fois à la précédente et à la prochaine.
Pour obtenir la demande, nous pouvons fouiller dans les internes d'une prise pour voir s'il y a quelque chose que nous pouvons abuser. Object.keys(socket)
renvoie le tableau suivant:
[
"connecting",
"_hadError",
"_handle",
"_parent",
"_Host",
"_readableState",
"readable",
"domain",
"_events",
"_eventsCount",
"_maxListeners",
"_writableState",
"writable",
"allowHalfOpen",
"destroyed",
"_bytesDispatched",
"_sockname",
"_pendingData",
"_pendingEncoding",
"server",
"_server",
"parser",
"_httpMessage"
]
Et, en effet, si nous nous penchons sur l'aspect suspect _pendingData
, Nous pouvons afficher la demande avant qu'elle ne soit envoyée:
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()); });
});
Cela renverra les en-têtes de demande envoyés comme réponse
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"))
http.request
A également la possibilité de passer votre propre connexion (createConnection
). Vous pouvez utiliser cette option pour fournir votre propre connexion créée, qui est "piped ()" à un flux de transformation de l'enregistreur.
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();
J'ai essayé d'implémenter le flux PassThrough
au lieu du Transform
. Cela m'a donné une erreur d'analyse HTTP lorsque j'ai canalisé le flux PassThrough vers la connexion. Je ne sais pas pourquoi être honnête.
Il est important d'inclure la flush: () => {}
, de la documentation
Cela sera appelé lorsqu'il n'y aura plus de données écrites à consommer, mais avant que l'événement "end" ne soit émis, signalant la fin du flux lisible.
https://nodejs.org/api/stream.html#stream_transform_flush_callback