Gdzie jest ciało w odpowiedzi http.get nodejs?

187

Czytam dokumenty na stronie http://nodejs.org/docs/v0.4.0/api/http.html#http.request , ale z jakiegoś powodu nie mogę znaleźć atrybutu body / data na zwróconym, gotowym obiekcie odpowiedzi.

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

> res.finished
true

> res._hasBody
true

Jest zakończony (http.get robi to za Ciebie), więc powinien mieć jakąś treść. Ale nie ma ciała, żadnych danych i nie mogę z nich odczytać. Gdzie ukrywa się ciało?

mikemaccana
źródło
7
Ponieważ żadna z odpowiedzi nie wspomina, skąd będziesz wiedzieć, kiedy datawydarzenia się skończą ... poprośres o "end"( nodejs.org/docs/latest/api/http.html#event_end_ )
SooDesuNe

Odpowiedzi:

172

Dokumenty http.request zawierają przykład otrzymywania treści odpowiedzi poprzez obsługę datazdarzenia:

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 robi to samo co http.request, tyle że wywołuje req.end()automatycznie.

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
źródło
15
Z jakiegoś powodu musiałem dodać res.setEncoding('utf8');do przykładu http.get. W przeciwnym razie nie dostałem HTML w chunkzmiennej.
SSH To
1
@SSHTo dlatego, że były to obiekty buforowe zawierające surowe dane. Jeśli chcesz od nich napisów, możesz także użyć chunk.toString (), opcjonalnie przekazując toString i kodując. To powiedziawszy, setEncoding jest prawdopodobnie bardziej wydajny.
skeggse
14
Zdarzenie „data” może być wywoływane wiele razy, a treść będzie dostarczana kawałek po kawałku. Przykład nie pokazuje, jak je skleić.
Andrej
4
@tfmontague. Zgoda! Zaskakujące ... tak wiele głosów poparcia dla odpowiedzi, która jest błędna u podstaw.
Sunny,
@tfmontague: POST requests typically use a response body, not GET.post żądanie mieć ciało i GET żądania nie robi, ale GET odpowiedź może mieć ciało.
Cyrbil,
135

Chcę również dodać, że http.ClientResponsezwrócone przez http.get()ma endzdarzenie, więc oto inny sposób, w jaki otrzymuję odpowiedź ciała:

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
źródło
13
Dziękuję za to! Wydarzenie „koniec” było dla mnie kluczowe, ponieważ musiałem przetworzyć treść odpowiedzi jako całość, a nie w częściach.
Daniel Gruszczyk
http.ClientResponsenie jest zwracany przez http.get() http.ClientRequestjest, zarówno zgodnie z aktualną dokumentacją, jak i dokumentacją powiązaną z oryginalnym plakatem.
Vince
54

Edycja: odpowiadanie sobie 6 lat później

Oczekujcie słów kluczowych jest najlepszym sposobem, aby uzyskać odpowiedź od żądania HTTP, unikając wywołania zwrotne i.then()

Musisz także użyć klienta HTTP, który zwraca Obietnice. http.get()nadal zwraca obiekt Request, więc to nie zadziała. Możesz użyć fetch, ale superagentjest dojrzałym klientem HTTP, który ma bardziej rozsądne ustawienia domyślne, w tym prostsze kodowanie ciągu zapytania, odpowiednio wykorzystując typy MIME, domyślnie JSON i inne typowe funkcje klienta HTTP. awaitpoczeka, aż obietnica będzie miała wartość - w tym przypadku odpowiedź HTTP!

const superagent = require('superagent');

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

Używając funkcji czekaj, kontrola po prostu przechodzi do następnego wiersza, gdy zwrócona przez nią obietnica superagent.get()ma wartość.

mikemaccana
źródło
3
To nie odpowiada na twoje pierwotne pytanie. W przykładowym kodzie resustawiono wartość zwracaną superagent.get(), a nie http.get(). http.get()zwraca wartość http.IncomingMessage, która nie ma textwłaściwości. To nie jest obiekt odpowiedzi, to obiekt żądania.
Vince
Dobra uwaga Vince Zmienię odpowiedź, aby była czystsza Używam klienta HTTP obsługującego obietnice.
mikemaccana
12

dataZdarzenie jest opalane wiele razy „kawałkami” ciała, ponieważ są one pobierane i w endprzypadku, gdy wszystkie kawałki zostały pobrane.

Teraz, gdy węzeł obsługuje obietnice , utworzyłem proste opakowanie, aby zwrócić połączone fragmenty za pomocą obietnicy:

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

Możesz go wywołać z funkcji asynchronicznej za pomocą:

const body = await httpGet('http://www.somesite.com');
nkron
źródło
11

Jeśli chcesz użyć .get, możesz to zrobić w ten sposób

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

});
użytkownik969714
źródło
2
Inne przykłady dały mi coś, co wyglądało na wartości szesnastkowe, gdy nie dołączałem tekstu do odpowiedzi fragmentu. Ustawienie kodowania wyświetlało poszukiwany dokument JSON. Dziękuję Ci!
Collin McGuire,
@CollinMcGuire, ponieważ były to obiekty buforowe zawierające surowe dane. Jeśli chcesz od nich napisów, możesz także użyć chunk.toString(), opcjonalnie przekazując toStringi kodując. To powiedziawszy, setEncodingjest prawdopodobnie bardziej wydajne.
skeggse
6

Musisz dodać detektor do żądania, ponieważ node.js działa tak asynchronicznie:

request.on('response', function (response) {
  response.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
 });
});
Skomski
źródło
2

Moduł igły jest również dobry, oto przykład, który używa needlemodułu

var needle = require('needle');

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

Porcja kawy tutaj:

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

I skompilowane

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 sierpnia
źródło
0

Nie można uzyskać treści odpowiedzi na podstawie wartości zwracanej http.get().

http.get()nie zwraca obiektu odpowiedzi. Zwraca obiekt żądania ( http.clientRequest). Zatem nie ma żadnego sposobu na uzyskanie treści odpowiedzi na podstawie wartości zwracanej http.get().

Wiem, że to stare pytanie, ale lektura dokumentacji, do której linkujesz, pokazuje, że miało to miejsce nawet po opublikowaniu.

Vince
źródło