Node.js: obtenga el cuerpo de la solicitud sin procesar usando Express

81

Cuando uso Express, y mi código es:

app.use(express.bodyParser());

¿Cómo obtendría el cuerpo de la solicitud sin procesar ?

haitao_wu
fuente
posible duplicado del cuerpo crudo
Jonathan Lonowski

Respuestas:

89

Edición 2: la versión 1.15.2 del módulo analizador de cuerpos introduce el modo sin procesar , que devuelve el cuerpo como un búfer . De forma predeterminada, también gestiona automáticamente la descompresión de desinflado y gzip. Uso de ejemplo:

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

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

De forma predeterminada, el optionsobjeto tiene las siguientes opciones predeterminadas:

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

Si desea que su analizador sin formato analice otros tipos MIME que no sean application/octet-stream, deberá cambiarlo aquí. También admitirá la coincidencia de comodines como */*o */application.


Nota: La siguiente respuesta es para versiones anteriores a Express 4, donde el middleware todavía estaba incluido con el marco. El equivalente moderno es el módulo analizador corporal , que debe instalarse por separado.

La rawBodypropiedad en Express estuvo disponible una vez, pero se eliminó desde la versión 1.5.1. Para obtener el cuerpo de la solicitud sin formato, debe instalar un middleware antes de usar bodyParser. También puede leer una discusión de GitHub al respecto aquí .

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

Ese middleware leerá el flujo de datos real y lo almacenará en la rawBodypropiedad de la solicitud. Luego puede acceder al cuerpo sin procesar de esta manera:

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

Editar: Parece que este método y bodyParser se niegan a coexistir, porque uno consumirá el flujo de solicitud antes que el otro, lo que hará que el que sea segundo nunca se active end, por lo que nunca llame next()y cuelgue su aplicación.

Lo más probable es que la solución más sencilla sea modificar la fuente de bodyParser, que encontrará en la línea 57 del analizador JSON de Connect. Así es como se vería la versión modificada.

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

Encontraría el archivo en esta ubicación:

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

hexacianuro
fuente
Parece que no podemos hacer esto. Si agregué este código, los eventos en \ node_modules \ express \ node_modules \ connect \ lib \ middleware \ urlencoded.js no se activarán. req.on ("datos"), req.on ("end") no disparado .
haitao_wu
Después de agregar su código, proceso mi publicación use este código app.post ("/ ajax", function (req, res) {res.send ('hello world, post');}); cuando el tipo de contenido de mi solicitud es application / x-www-form-urlencoded, el servidor no responderá "hola mundo, publicar"
haitao_wu
la ubicación del archivo es incorrecta en mi caso. No tengo un módulo de conexión en los node_modules de express (> 4.0.0) aún no he encontrado la nueva ubicación
Sam Vloeberghs
Connect no es una dependencia en Express 4 y, por lo tanto, no contiene el módulo Body Parser. Si aún lo necesita, lo encontrará aquí .
hexacianuro
1
@hexacyanide ¿Puede actualizar su respuesta e incluir una referencia al último software intermedio de analizador corporal ? El módulo ahora incluye el middleware de analizador de cuerpo sin procesar . Esto puede ser útil para los usuarios de Google que buscan un método para obtener el cuerpo en bruto.
eAbi
47

Obtuve una solución que funciona bien con bodyParser, usando la verifydevolución de llamada en bodyParser. En este código, lo estoy usando para obtener un sha1 del contenido y también para obtener el cuerpo en bruto.

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

    }
}));

Soy nuevo en Node.js y express.js (¡comencé ayer, literalmente!), Así que me gustaría escuchar comentarios sobre esta solución.

Tiago A.
fuente
3
Me gusta mucho esta solución. Simplemente incluí req.rawBody = buf.toString();y saqué el resto de la verifyfunción, porque eso era todo lo que necesitaba y funcionó a la perfección. ¡No es necesario cambiar el código fuente de bodyParser!
Greg
+1 pero mi problema ahora es que necesito una función asíncrona para verificar si esta solicitud se envió previamente o no: /
Renato Gama
3
muy agradable. puedo sugerirreq.rawBody = buf.toString(encoding);
shaharsol
2
Esto capturará solo application/jsonsolicitudes
Pavel Evstigneev
35

Esta solución funcionó para mí:

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

Cuando uso una solución req.on('data', function(chunk) { });que no funciona en el cuerpo de la solicitud fragmentada.

Pavel Evstigneev
fuente
Esto se ocupó de cada escenario importante de datos entrantes en varias partes de la solicitud.
TWright
2
Estaba intentando verificar el hmac para un webhook de la aplicación Shopify, y esto funcionó para mí. Seguí aproximadamente este ejemplo: gist.github.com/andjosh/5c4f0244914adfd312e4 .
Chad Johnson
29

TENGA CUIDADO con esas otras respuestas, ya que no funcionarán correctamente con bodyParser si también desea admitir json, urlencoded, etc. Para que funcione con bodyParser, debe condicionar a su controlador para que solo se registre en los Content-Typeencabezados que usted preocuparse, al igual que bodyParser.

Para obtener el contenido del cuerpo en bruto de una solicitud con Content-Type: "text/plain"en req.rawBodyque puede hacer:

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
fuente
3
+1. Probé una de las soluciones anteriores y luego todas mis publicaciones GET y json fallaron. Las soluciones anteriores son técnicamente correctas para la pregunta, pero si está manejando solicitudes más diversas con datos en más de una forma, necesitará esto.
¿Qué datos hay aquí? ¿Es la variable que enviamos desde la interfaz de usuario?
Saras Arya
app.use(bodyParser.urlencoded({limit: '80mb', extended: true})); app.use(bodyParser.json({limit: '80mb'})); app.use(bodyParser.raw({type: 'application/octet-stream'})) Esto también serviría.
Soumya Kanti
15

Esta es una variación de la respuesta de hexacianuro anterior. Este middleware también maneja el evento 'datos' pero no espera a que se consuman los datos antes de llamar al 'siguiente'. De esta forma, tanto este middleware como bodyParser pueden coexistir, consumiendo el flujo en paralelo.

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
fuente
2
Esto no parece funcionar en cuerpos largos, que se cortan temprano.
Adam Lockhart
Funcionó perfectamente, me salvó. Gracias.
hakazvaka
Confirmo que esto también funciona para archivos grandes. Intenté enviar un archivo de texto de 1,5 MB y todos los datos se recibieron correctamente. Gracias
ATOzTOA
@AdamLockhart: ¿de qué tamaño fueron sus solicitudes que se cortaron?
UpTheCreek
@UpTheCreek, ha pasado un tiempo. No estoy seguro. Mis últimas cosas no usan este fragmento, pero si otros informan que no hay problemas, es posible que haya sido un error que se ha solucionado.
Adam Lockhart
-1

Use body-parser Analice el cuerpo con lo que será:

app.use(bodyParser.text());

app.use(bodyParser.urlencoded());

app.use(bodyParser.raw());

app.use(bodyParser.json());

es decir. Si se supone que debe obtener un archivo de texto sin formato, ejecute .text().

Eso es lo que el analizador corporal admite actualmente

mewc
fuente