Node.js - Ruft den Rohanforderungshauptteil mit Express ab


Antworten:


89

Edit 2: Release 1.15.2 des Body-Parser-Moduls führt den Raw-Modus ein , der den Body als Puffer zurückgibt . Standardmäßig werden auch die Dekomprimierung von Deflate und GZIP automatisch verarbeitet. Anwendungsbeispiel:

var bodyParser = require('body-parser');
app.use(bodyParser.raw(options));

app.get(path, function(req, res) {
  // req.body is a Buffer object
});

Standardmäßig verfügt das optionsObjekt über die folgenden Standardoptionen:

var options = {
  inflate: true,
  limit: '100kb',
  type: 'application/octet-stream'
};

Wenn Ihr Raw-Parser andere MIME-Typen als analysieren soll application/octet-stream, müssen Sie ihn hier ändern. Es wird auch Wildcard-Matching wie */*oder unterstützt */application.


Hinweis: Die folgende Antwort bezieht sich auf Versionen vor Express 4, in denen Middleware noch im Framework enthalten war. Das moderne Äquivalent ist das Body-Parser- Modul, das separat installiert werden muss.

Die rawBodyEigenschaft in Express war einmal verfügbar, wurde jedoch seit Version 1.5.1 entfernt. Um den unformatierten Anforderungshauptteil zu erhalten, müssen Sie Middleware einfügen, bevor Sie den bodyParser verwenden können. Sie können auch eine GitHub Diskussion darüber lesen Sie hier .

app.use(function(req, res, next) {
  req.rawBody = '';
  req.setEncoding('utf8');

  req.on('data', function(chunk) { 
    req.rawBody += chunk;
  });

  req.on('end', function() {
    next();
  });
});
app.use(express.bodyParser());

Diese Middleware liest aus dem tatsächlichen Datenstrom und speichert ihn in der rawBodyEigenschaft der Anforderung. Sie können dann wie folgt auf den Rohkörper zugreifen:

app.post('/', function(req, res) {
  // do something with req.rawBody
  // use req.body for the parsed body
});

Bearbeiten: Es scheint, dass diese Methode und bodyParser sich weigern, nebeneinander zu existieren, da einer den Anforderungsstrom vor dem anderen verbraucht, was dazu führt, dass derjenige, der an zweiter Stelle steht, niemals feuert end, also niemals aufruft next()und Ihre Anwendung hängt.

Die einfachste Lösung wäre höchstwahrscheinlich, die Quelle von bodyParser zu ändern, die Sie in Zeile 57 des JSON-Parsers von Connect finden würden . So würde die modifizierte Version aussehen.

var buf = '';
req.setEncoding('utf8');
req.on('data', function(chunk){ buf += chunk });
req.on('end', function() {
  req.rawBody = buf;
  var first = buf.trim()[0];
  ...
});

Sie finden die Datei an dieser Stelle:

/node_modules/express/node_modules/connect/lib/middleware/json.js.


Es scheint, wir können das nicht tun. Wenn ich diesen Code hinzugefügt habe, werden die Ereignisse in \ node_modules \ express \ node_modules \ connect \ lib \ middleware \ urlencoded.js nicht ausgelöst. req.on ("data"), req.on ("end") wurde nicht ausgelöst .
haitao_wu

Nachdem ich Ihren Code hinzugefügt habe, verarbeite ich meinen Beitrag mit diesem Code app.post ("/ ajax", Funktion (req, res) {res.send ('Hallo Welt, Beitrag');}); Wenn der Inhaltstyp meiner Anfrage application / x-www-form-urlencoded ist, antwortet der Server nicht "Hallo Welt, Post"
haitao_wu

Der Speicherort der Datei ist in meinem Fall falsch. Ich habe kein Verbindungsmodul in den Knotenmodulen von Express (> 4.0.0). Ich habe den neuen Speicherort noch nicht gefunden
Sam Vloeberghs

Connect ist in Express 4 keine Abhängigkeit und enthält daher nicht das Body Parser-Modul. Wenn Sie es noch brauchen, finden Sie es hier .
Hexacyanid

1
@hexacyanide Können Sie bitte Ihre Antwort aktualisieren und einen Verweis auf die neueste Body-Parser- Middleware hinzufügen ? Das Modul enthält jetzt die Raw-Body-Parser-Middleware . Dies kann für Googler hilfreich sein, die nach einer Methode suchen, um den Rohkörper zu erhalten.
eAbi

46

Ich habe eine Lösung, die mit bodyParser gut funktioniert, indem ich den verifyRückruf in bodyParser verwende. In diesem Code verwende ich es, um einen sha1 des Inhalts und auch den Rohkörper zu erhalten.

app.use(bodyParser.json({
    verify: function(req, res, buf, encoding) {

        // sha1 content
        var hash = crypto.createHash('sha1');
        hash.update(buf);
        req.hasha = hash.digest('hex');
        console.log("hash", req.hasha);

        // get rawBody        
        req.rawBody = buf.toString();
        console.log("rawBody", req.rawBody);

    }
}));

Ich bin neu in Node.js und express.js (buchstäblich gestern gestartet!), Daher würde ich gerne Kommentare zu dieser Lösung hören.


3
Diese Lösung gefällt mir sehr gut. Ich habe nur req.rawBody = buf.toString();den Rest aufgenommen und den Rest aus der verifyFunktion genommen, weil das alles war, was ich brauchte, und es hat wunderbar funktioniert. Der bodyParser-Quellcode muss nicht geändert werden!
Greg

+1 aber mein Problem ist jetzt, dass ich eine asynchrone Funktion benötige, um zu überprüfen, ob diese Anfrage zuvor gesendet wurde oder nicht: /
Renato Gama

3
Sehr schön. Darf ich vorschlagenreq.rawBody = buf.toString(encoding);
Shaharsol

2
Dies wird nur application/jsonAnfragen erfassen
Pavel Evstigneev

34

Diese Lösung hat bei mir funktioniert:

var rawBodySaver = function (req, res, buf, encoding) {
  if (buf && buf.length) {
    req.rawBody = buf.toString(encoding || 'utf8');
  }
}

app.use(bodyParser.json({ verify: rawBodySaver }));
app.use(bodyParser.urlencoded({ verify: rawBodySaver, extended: true }));
app.use(bodyParser.raw({ verify: rawBodySaver, type: '*/*' }));

Wenn ich eine Lösung verwende req.on('data', function(chunk) { });, funktioniert sie nicht mit einem blockierten Anforderungshauptteil.


Dies kümmerte sich um alle wichtigen Szenarien eingehender Daten in verschiedenen Teilen der Anfrage.
TWright

2
Ich habe versucht, den hmac für einen Shopify-App-Webhook zu überprüfen, und das hat bei mir funktioniert. Ich bin diesem Beispiel grob gefolgt: gist.github.com/andjosh/5c4f0244914adfd312e4 .
Chad Johnson

28

Seien Sie vorsichtig mit diesen anderen Antworten, da sie mit bodyParser nicht richtig funktionieren, wenn Sie auch json, urlencoded usw. unterstützen möchten. Damit es mit bodyParser funktioniert, sollten Sie Ihren Handler so konditionieren, dass er sich nur in den Headern registriert, die Content-TypeSie haben kümmern sich darum, genau wie bodyParser selbst.

Um den Rohkörperinhalt einer Anfrage mit Content-Type: "text/plain"in zu erhalten, haben req.rawBodySie folgende Möglichkeiten:

app.use(function(req, res, next) {
  var contentType = req.headers['content-type'] || ''
    , mime = contentType.split(';')[0];

  if (mime != 'text/plain') {
    return next();
  }

  var data = '';
  req.setEncoding('utf8');
  req.on('data', function(chunk) {
    data += chunk;
  });
  req.on('end', function() {
    req.rawBody = data;
    next();
  });
});

3
+1. Ich habe eine der oben genannten Lösungen ausprobiert und dann sind alle meine GETs und JSON-Posts fehlgeschlagen. Die oben genannten Lösungen sind für die Frage technisch korrekt. Wenn Sie jedoch unterschiedlichere Anforderungen mit Daten in mehr als einer Form bearbeiten, benötigen Sie diese.

Was sind Daten hier? Ist es die Variable, die wir von der Benutzeroberfläche senden?
Saras Arya

app.use(bodyParser.urlencoded({limit: '80mb', extended: true})); app.use(bodyParser.json({limit: '80mb'})); app.use(bodyParser.raw({type: 'application/octet-stream'})) Dies würde auch reichen.
Soumya Kanti

15

Dies ist eine Variation der obigen Antwort von Hexacyanid. Diese Middleware behandelt auch das Ereignis 'Daten', wartet jedoch nicht darauf, dass die Daten verbraucht werden, bevor sie 'Weiter' aufruft. Auf diese Weise können sowohl diese Middleware als auch bodyParser nebeneinander existieren und den Stream parallel verbrauchen.

app.use(function(req, res, next) {
  req.rawBody = '';
  req.setEncoding('utf8');

  req.on('data', function(chunk) { 
    req.rawBody += chunk;
  });

  next();
});
app.use(express.bodyParser());


2
Dies scheint bei langen Körpern nicht zu funktionieren, die früh abgeschnitten werden.
Adam Lockhart

Hat perfekt funktioniert, hat mich gerettet. Vielen Dank.
Hakazvaka

Ich bestätige, dass dies auch für große Dateien funktioniert. Ich habe versucht, eine Textdatei von 1,5 MB zu senden, und die gesamten Daten wurden ordnungsgemäß empfangen. Vielen Dank
ATOzTOA

@AdamLockhart - In welcher Größe wurden Ihre Anfragen gekürzt?
UpTheCreek

@ UpTheCreek, schon eine Weile. Nicht sicher. Meine neuesten Inhalte verwenden dieses Snippet nicht, aber wenn andere keine Probleme melden, wurde möglicherweise ein Fehler behoben.
Adam Lockhart

-1

Verwenden Sie Body-Parser Analysieren Sie den Körper mit dem, was er sein wird:

app.use(bodyParser.text());

app.use(bodyParser.urlencoded());

app.use(bodyParser.raw());

app.use(bodyParser.json());

dh. Wenn Sie eine Rohtextdatei erhalten sollen, führen Sie diese aus .text().

Das unterstützt Body-Parser derzeit

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.