Node.js - pobierz surową treść żądania za pomocą Express

81

Kiedy używam Express, a mój kod to:

app.use(express.bodyParser());

Jak uzyskać treść surowego żądania ?

haitao_wu
źródło
możliwy duplikat surowego ciała
Expressjs

Odpowiedzi:

89

Edycja 2: Wersja 1.15.2 modułu analizatora treści treści wprowadza tryb surowy , który zwraca treść jako bufor . Domyślnie obsługuje również automatycznie dekompresję deflate i gzip. Przykładowe użycie:

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

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

Domyślnie optionsobiekt ma następujące domyślne opcje:

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

Jeśli chcesz, aby twój surowy parser parsował inne typy MIME inne niż application/octet-stream, musisz to zmienić tutaj. Obsługuje również dopasowywanie symboli wieloznacznych, takich jak */*lub */application.


Uwaga: następująca odpowiedź dotyczy wersji wcześniejszych niż Express 4, w których oprogramowanie pośredniczące było nadal dołączane do platformy. Współczesnym odpowiednikiem jest moduł parsera treści , który należy zainstalować osobno.

rawBodyNieruchomość Ekspresowe niegdyś dostępny, ale usunięto od wersji 1.5.1. Aby uzyskać treść surowego żądania, przed użyciem metody bodyParser musisz zainstalować oprogramowanie pośredniczące. Możesz również przeczytać dyskusję na ten temat w serwisie GitHub tutaj .

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());

To oprogramowanie pośredniczące odczyta rzeczywisty strumień danych i zapisze go we rawBodywłaściwości żądania. Następnie możesz uzyskać dostęp do surowego ciała w następujący sposób:

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

Edycja: Wygląda na to, że ta metoda i bodyParser odmawiają współistnienia, ponieważ jeden z nich będzie zużywał strumień żądania przed drugim, co prowadzi do tego, który z nich jest drugi, aby nigdy nie uruchamiać end, a zatem nigdy nie wywoływać next()i zawieszać aplikacji.

Najprostszym rozwiązaniem byłoby najprawdopodobniej zmodyfikowanie źródła bodyParser, które można znaleźć w linii 57 parsera JSON Connect. Tak wyglądałaby zmodyfikowana wersja.

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

Plik można znaleźć w tej lokalizacji:

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

heksacyjanek
źródło
Wygląda na to, że nie możemy tego zrobić. Jeśli dodałem ten kod, zdarzenia w \ node_modules \ express \ node_modules \ connect \ lib \ middleware \ urlencoded.js nie zostaną uruchomione. req.on ("data"), req.on ("end") nie uruchomione .
haitao_wu,
Po dodaniu twojego kodu, przetwarzam mój post. Użyj tego kodu app.post ("/ ajax", function (req, res) {res.send ('hello world, post');}); gdy typ zawartości mojego żądania to application / x-www-form-urlencoded, serwer nie odpowie „hello world, post”
haitao_wu
lokalizacja pliku jest nieprawidłowa w moim przypadku .. Nie mam modułu connect w node_modules programu express (> 4.0.0) Nie znalazłem jeszcze nowej lokalizacji
Sam Vloeberghs
Connect nie jest zależnością w Express 4 i dlatego nie zawiera modułu Body Parser. Jeśli nadal go potrzebujesz, znajdziesz go tutaj .
heksacyjanid
1
@hexacyanide Czy możesz zaktualizować swoją odpowiedź i dołączyć odniesienie do najnowszego oprogramowania pośredniczącego z parserem treści ? Moduł zawiera teraz oprogramowanie pośredniczące typu raw-body-parser . Może to być pomocne dla pracowników Google, którzy szukają metody na uzyskanie surowego treści.
eAbi
47

Mam rozwiązanie, które dobrze współgra z bodyParser, używając verifywywołania zwrotnego w bodyParser. W tym kodzie używam go, aby uzyskać sha1 zawartości, a także uzyskać surowe ciało.

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);

    }
}));

Jestem nowy w Node.js i express.js (dosłownie wystartowałem wczoraj!), Więc chciałbym usłyszeć komentarze na temat tego rozwiązania.

Tiago A.
źródło
3
Bardzo podoba mi się to rozwiązanie. Po prostu włączyłem req.rawBody = buf.toString();i wyjąłem resztę z verifyfunkcji, ponieważ to było wszystko, czego potrzebowałem, i działało pięknie. Nie ma potrzeby zmiany kodu źródłowego bodyParser!
Greg
+1, ale teraz moim problemem jest to, że potrzebuję funkcji asynchronicznej, aby sprawdzić, czy ta prośba została wcześniej wysłana, czy nie: /
Renato Gama
3
bardzo dobrze. czy mogę zasugerowaćreq.rawBody = buf.toString(encoding);
shaharsol
2
Spowoduje to przechwycenie tylko application/jsonżądań
Pavel Evstigneev
35

To rozwiązanie zadziałało dla mnie:

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: '*/*' }));

Kiedy używam rozwiązania, req.on('data', function(chunk) { });które nie działa na podzielonej treści żądania.

Pavel Evstigneev
źródło
Zadbało to o każdy główny scenariusz napływających danych w różnych częściach żądania.
TWright
2
Próbowałem zweryfikować hmac dla webhooka aplikacji Shopify i to zadziałało. Z grubsza podążyłem za tym przykładem: gist.github.com/andjosh/5c4f0244914adfd312e4 .
Chad Johnson,
29

UWAŻAJ na te inne odpowiedzi, ponieważ nie będą one działać poprawnie z bodyParser, jeśli chcesz również obsługiwać json, urlencoded itp. Aby sprawić, że będzie działać z bodyParser, powinieneś ustawić program obsługi, aby rejestrował się tylko w Content-Typenagłówku (ach) zależy, tak jak robi to sam bodyParser.

Aby uzyskać nieprzetworzoną treść żądania za pomocą polecenia Content-Type: "text/plain"into req.rawBody, możesz:

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();
  });
});
nortron
źródło
3
+1. Wypróbowałem jedno z powyższych rozwiązań, a następnie wszystkie moje posty GET i json zawiodły. Powyższe rozwiązania są technicznie poprawne dla tego pytania, ale jeśli obsługujesz bardziej zróżnicowane żądania z danymi w więcej niż jednej formie, będziesz tego potrzebować.
Co to są dane? czy jest to zmienna, którą wysyłamy z interfejsu użytkownika?
Saras Arya
app.use(bodyParser.urlencoded({limit: '80mb', extended: true})); app.use(bodyParser.json({limit: '80mb'})); app.use(bodyParser.raw({type: 'application/octet-stream'})) To też by się przydało.
Soumya Kanti
15

To jest odmiana odpowiedzi heksacyjanku powyżej. To oprogramowanie pośredniczące obsługuje również zdarzenie „data”, ale nie czeka na wykorzystanie danych przed wywołaniem „next”. W ten sposób zarówno to oprogramowanie pośredniczące, jak i bodyParser mogą współistnieć, jednocześnie zużywając strumień.

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

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

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

oferei
źródło
2
Wydaje się, że to nie działa na długich ciałach, które wcześnie się odcinają.
Adam Lockhart
Działał doskonale, uratował mnie. Dziękuję Ci.
hakazvaka
Potwierdzam, że działa to również w przypadku dużych plików. Próbowałem wysłać plik tekstowy o rozmiarze 1,5 MB i wszystkie dane zostały odebrane poprawnie. Dziękuję
ATOzTOA
@AdamLockhart - jaki rozmiar były Twoje żądania, które zostały obcięte?
UpTheCreek
@UpTheCreek, minęło trochę czasu. Niepewny. Moje najnowsze rzeczy nie używają tego fragmentu, ale jeśli inni nie zgłaszają żadnych problemów, może to być błąd, który został naprawiony.
Adam Lockhart
-1

Użyj parsera treści Przeanalizuj treść z tym, co będzie:

app.use(bodyParser.text());

app.use(bodyParser.urlencoded());

app.use(bodyParser.raw());

app.use(bodyParser.json());

to znaczy. Jeśli masz pobrać surowy plik tekstowy, uruchom .text().

To właśnie obsługuje obecnie analizator treści

mewc
źródło