Onde está o corpo em uma resposta http.get do nodejs?

187

Estou lendo os documentos em http://nodejs.org/docs/v0.4.0/api/http.html#http.request , mas por algum motivo, não consigo encontrar o atributo body / data no objeto de resposta retornado e finalizado.

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

> res.finished
true

> res._hasBody
true

Está concluído (http.get faz isso por você), portanto, ele deve ter algum tipo de conteúdo. Mas não há corpo, nem dados, e eu não consigo ler. Onde o corpo está escondido?

mikemaccana
fonte
7
Como nenhuma das respostas mencionar como você saberá quando os dataeventos são feitas .. ter seu resouvir "end"( nodejs.org/docs/latest/api/http.html#event_end_ )
SooDesuNe

Respostas:

172

Os documentos http.request contêm exemplo de como receber o corpo da resposta por meio do dataevento de manipulação :

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 faz o mesmo que http.request, exceto que ele chama req.end()automaticamente.

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
fonte
15
Por alguma razão, eu tive que adicionar res.setEncoding('utf8');ao exemplo http.get. Caso contrário, não obtive HTML na chunkvariável.
SSH This
1
@SSHIsso é porque eram objetos de buffer que contêm dados brutos. Se você quisesse strings deles, também poderia usar chunk.toString (), opcionalmente passando toString e codificação. Dito isto, setEncoding é provavelmente mais eficiente.
Skeggse
14
O evento "data" pode ser chamado várias vezes e você obterá o conteúdo, peça por peça. O exemplo não mostra como colá-los juntos.
Andrej
4
@tfmontague. Acordado! Surpreendente ... tantos votos positivos por uma resposta que é falha no seu próprio fundamento.
Sunny
@tfmontague: a solicitação dePOST requests typically use a response body, not GET. postagem tem um corpo e a solicitação GET não, mas uma resposta GET pode ter um corpo.
Cyrbil # 5/15
135

Também quero acrescentar que o http.ClientResponseretornado por http.get()tem um endevento, então aqui está outra maneira de receber a resposta do corpo:

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
fonte
13
Obrigado por isso! O evento 'final' foi crucial para mim, pois tive que processar o corpo da resposta como um todo, e não em pedaços.
precisa
http.ClientResponsenão é retornado por http.get() http.ClientRequestis, de acordo com a documentação atual e a documentação vinculada pelo pôster original.
Vince
54

Edit: respondendo a si mesmo 6 anos depois

A palavra - chave wait é a melhor maneira de obter uma resposta de uma solicitação HTTP, evitando retornos de chamada e.then()

Você também precisará usar um cliente HTTP que retorne promessas. http.get()ainda retorna um objeto Request, para que não funcione. Você poderia usar fetch, mas superagenté um cliente HTTP maduro, que possui padrões mais razoáveis, incluindo codificação de cadeia de consulta mais simples, usando corretamente tipos MIME, JSON por padrão e outros recursos comuns do cliente HTTP. awaitesperará até que a Promessa tenha um valor - nesse caso, uma resposta HTTP!

const superagent = require('superagent');

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

Usando aguardar, o controle simplesmente passa para a próxima linha quando a promessa retornada por superagent.get()tiver um valor.

mikemaccana
fonte
3
Isso não responde à sua pergunta original. No seu código de exemplo, resé definido como o valor de retorno de superagent.get(), não http.get(). http.get()retorna um http.IncomingMessageque não possui uma textpropriedade. Não é o objeto de resposta, é o objeto de solicitação.
Vince
Bom ponto Vince, eu vou editar a resposta para torná-la mais limpa. Estou usando um cliente HTTP que suporta Promises.
Mikemaccana #
12

O dataevento é disparado várias vezes com 'pedaços' do corpo à medida que são baixados e um endevento quando todos os pedaços foram baixados.

Com o Nó suportando Promises agora, criei um wrapper simples para retornar os pedaços concatenados por meio de um Promise:

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

Você pode chamá-lo de uma função assíncrona com:

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

Se você deseja usar .get, pode fazê-lo assim

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

});
user969714
fonte
2
Os outros exemplos me deram o que pareciam valores hexadecimais quando eu não incluí texto com a resposta em bloco. A definição da codificação exibiu o documento JSON que eu estava procurando. Obrigado!
precisa
@CollinMcGuire é porque eram objetos de buffer que contêm dados brutos. Se você quisesse strings deles, também poderia usar chunk.toString(), opcionalmente passando toStringe codificando. Dito isto, setEncodingé provavelmente mais eficiente.
Skeggse
6

Você precisa adicionar um ouvinte à solicitação porque o node.js funciona de forma assíncrona assim:

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

O módulo de agulha também é bom, aqui está um exemplo que usa o needlemódulo

var needle = require('needle');

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

Uma porção de café aqui:

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

E 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
    }));
  });
});
18augst
fonte
0

Você não pode obter o corpo da resposta a partir do valor de retorno de http.get().

http.get()não retorna um objeto de resposta. Retorna o objeto de solicitação ( http.clientRequest). Portanto, não há como obter o corpo da resposta a partir do valor de retorno de http.get().

Sei que é uma pergunta antiga, mas ler a documentação à qual você vinculou mostra que esse era o caso mesmo quando você a postou.

Vince
fonte