¿Dónde está el cuerpo en una respuesta http.get de nodejs?

187

Estoy leyendo los documentos en http://nodejs.org/docs/v0.4.0/api/http.html#http.request , pero por alguna razón, parece que no puedo encontrar el atributo body / data en el objeto de respuesta devuelto, terminado.

> var res = http.get({host:'www.somesite.com', path:'/'})

> res.finished
true

> res._hasBody
true

Está terminado (http.get lo hace por usted), por lo que debería tener algún tipo de contenido. Pero no hay cuerpo, ni datos, y no puedo leerlo. ¿Dónde se esconde el cuerpo?

mikemaccana
fuente
77
Como ninguna de las respuestas menciona cómo sabrá cuándo datase realizan los eventos ... resescuche "end"( nodejs.org/docs/latest/api/http.html#event_end_ )
SooDesuNe

Respuestas:

172

http.request docs contiene ejemplos de cómo recibir el cuerpo de la respuesta a través del dataevento de manejo :

var options = {
  host: 'www.google.com',
  port: 80,
  path: '/upload',
  method: 'POST'
};

var req = http.request(options, function(res) {
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');
  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

// write data to request body
req.write('data\n');
req.write('data\n');
req.end();

http.get hace lo mismo que http.request excepto que llama req.end()automáticamente.

var options = {
  host: 'www.google.com',
  port: 80,
  path: '/index.html'
};

http.get(options, function(res) {
  console.log("Got response: " + res.statusCode);

  res.on("data", function(chunk) {
    console.log("BODY: " + chunk);
  });
}).on('error', function(e) {
  console.log("Got error: " + e.message);
});
yojimbo87
fuente
15
Por alguna razón, tuve que agregar res.setEncoding('utf8');al ejemplo http.get. De lo contrario, no obtuve HTML en la chunkvariable.
SSH Este
1
@SSH Esto se debe a que eran objetos Buffer que contenían datos sin procesar. Si querías cadenas de ellos, también podrías usar chunk.toString (), opcionalmente pasando aString y codificando. Dicho esto, setEncoding es probablemente más eficiente.
skeggse
14
El evento "datos" puede llamarse varias veces y obtendrá el contenido pieza por pieza. El ejemplo no muestra cómo pegarlos.
Andrej
44
@tfmontague. ¡Convenido! Sorprendente ... tantos votos a favor por una respuesta que es defectuosa en su base.
Soleado
@tfmontague: la solicitud dePOST requests typically use a response body, not GET. publicación tiene un cuerpo y la solicitud GET no, pero una respuesta GET puede tener un cuerpo.
Cyrbil
135

También quiero agregar que el http.ClientResponsedevuelto por http.get()tiene un endevento, así que aquí hay otra forma en que recibo la respuesta del cuerpo:

var options = {
  host: 'www.google.com',
  port: 80,
  path: '/index.html'
};

http.get(options, function(res) {
  var body = '';
  res.on('data', function(chunk) {
    body += chunk;
  });
  res.on('end', function() {
    console.log(body);
  });
}).on('error', function(e) {
  console.log("Got error: " + e.message);
}); 
bizi
fuente
13
¡Gracias por eso! El evento 'final' fue crucial para mí, ya que tuve que procesar el cuerpo de respuesta como un todo, en lugar de hacerlo en trozos.
Daniel Gruszczyk
http.ClientResponseno es devuelto por http.get() http.ClientRequestes, de acuerdo con la documentación actual y la documentación vinculada al póster original.
Vince
54

Editar: respondiendo a mí mismo 6 años después

La palabra clave esperar es la mejor manera de obtener una respuesta de una solicitud HTTP, evitando devoluciones de llamada y.then()

También deberá usar un cliente HTTP que devuelva Promesas. http.get()todavía devuelve un objeto Solicitud, por lo que no funcionará. Podría usar fetch, pero superagentes un cliente HTTP maduro que presenta valores predeterminados más razonables, incluida una codificación de cadena de consulta más simple, que usa correctamente los tipos mime, JSON de forma predeterminada y otras características comunes del cliente HTTP. awaitesperará hasta que Promise tenga un valor, en este caso, ¡una respuesta HTTP!

const superagent = require('superagent');

(async function(){
  const response = await superagent.get('https://www.google.com')
  console.log(response.text)
})();

Usando esperar, el control simplemente pasa a la siguiente línea una vez que la promesa devuelta superagent.get()tiene un valor.

mikemaccana
fuente
3
Esto no responde a tu pregunta original. En su código de ejemplo, resse establece en el valor de retorno de superagent.get(), no http.get(). http.get()devuelve un http.IncomingMessageque no tiene una textpropiedad. No es el objeto de respuesta, es el objeto de solicitud.
Vince
Buen punto, Vince. Editaré la respuesta para que sea más limpia. Estoy usando un cliente HTTP que admite Promesas.
mikemaccana
12

El dataevento se dispara varias veces con 'fragmentos' del cuerpo a medida que se descargan y un endevento cuando todos los fragmentos se han descargado.

Ahora que Node admite Promesas , creé un contenedor simple para devolver los fragmentos concatenados a través de una Promesa:

const httpGet = url => {
  return new Promise((resolve, reject) => {
    http.get(url, res => {
      res.setEncoding('utf8');
      let body = ''; 
      res.on('data', chunk => body += chunk);
      res.on('end', () => resolve(body));
    }).on('error', reject);
  });
};

Puede llamarlo desde una función asíncrona con:

const body = await httpGet('http://www.somesite.com');
nkron
fuente
11

Si quieres usar .get puedes hacerlo así

http.get(url, function(res){
    res.setEncoding('utf8');
    res.on('data', function(chunk){
        console.log(chunk);
    });

});
usuario969714
fuente
2
Los otros ejemplos me dieron lo que parecían valores hexadecimales cuando no incluí texto con la respuesta fragmentaria. Al configurar la codificación se muestra el documento JSON que estaba buscando. ¡Gracias!
Collin McGuire
@CollinMcGuire es porque eran objetos de Buffer que contenían datos sin procesar. Si quisieras cadenas de ellas, también podrías usarlas chunk.toString(), opcionalmente pasando toStringy codificando. Dicho esto, setEncodinges probable que sea más eficiente.
skeggse
6

Debe agregar un escucha a la solicitud porque node.js funciona de forma asíncrona de esa manera:

request.on('response', function (response) {
  response.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
 });
});
Skomski
fuente
2

El módulo de aguja también es bueno, aquí hay un ejemplo que usa el needlemódulo

var needle = require('needle');

needle.get('http://www.google.com', function(error, response) {
  if (!error && response.statusCode == 200)
    console.log(response.body);
});
Tulasiram
fuente
0

Una porción de café aquí:

# My little helper
read_buffer = (buffer, callback) ->
  data = ''
  buffer.on 'readable', -> data += buffer.read().toString()
  buffer.on 'end', -> callback data

# So request looks like
http.get 'http://i.want.some/stuff', (res) ->
  read_buffer res, (response) ->
    # Do some things with your response
    # but don't do that exactly :D
    eval(CoffeeScript.compile response, bare: true)

Y compilado

var read_buffer;

read_buffer = function(buffer, callback) {
  var data;
  data = '';
  buffer.on('readable', function() {
    return data += buffer.read().toString();
  });
  return buffer.on('end', function() {
    return callback(data);
  });
};

http.get('http://i.want.some/stuff', function(res) {
  return read_buffer(res, function(response) {
    return eval(CoffeeScript.compile(response, {
      bare: true
    }));
  });
});
18 de agosto
fuente
0

No puede obtener el cuerpo de la respuesta a partir del valor de retorno de http.get().

http.get()no devuelve un objeto de respuesta. Devuelve el objeto de solicitud ( http.clientRequest). Por lo tanto, no hay forma de obtener el cuerpo de la respuesta a partir del valor de retorno de http.get().

Sé que es una pregunta antigua, pero leer la documentación que vinculaste muestra que este era el caso incluso cuando la publicaste.

Vince
fuente