2008-08-19 10 views
12

Mam problemy z czytania „pakietowego” odpowiedzi przy użyciu StreamReader do odczytu strumienia zwracanego przez GetResponseStream() o HttpWebResponse:Reading „pakietowego” odpowiedź z HttpWebResponse

// response is an HttpWebResponse 
StreamReader reader = new StreamReader(response.GetResponseStream()); 
string output = reader.ReadToEnd(); // throws exception... 

Gdy jest metoda reader.ReadToEnd() o nazwie Otrzymuję następujący System.IO.IOException: Nie można odczytać danych z połączenia transportowego: Połączenie zostało zamknięte.

Powyższy kod działa poprawnie, gdy serwer zwraca odpowiedź "nieobciąganą".

Jedynym sposobem, w jaki udało mi się go uruchomić, jest użycie HTTP/1.0 dla początkowego żądania (zamiast domyślnego HTTP/1.1), ale wydaje się to być kiepską pracą.

Wszelkie pomysły?


@Chuck

Twoje rozwiązanie działa całkiem dobrze. Nadal rzuca to samo IOExeception na ostatnim Read(). Ale po sprawdzeniu zawartości StringBuilder wygląda na to, że wszystkie dane zostały odebrane. Być może po prostu muszę owinąć Read() w try-catch i połknąć "błąd".

+0

Aby przeczytać pakietowego odpowiedź, trzeba wykonać http://en.wikipedia.org/wiki/Chunked_transfer_encoding –

+0

widzę ten problem z .NET 4.6 połączenie z interfejsem REST API PowerDNS 3.4.5. Rozwiązania nie pomagają. Jeśli połknę wyjątek, stracę część odpowiedzi. –

Odpowiedz

4

Nie próbowałem tego z "chunked" odpowiedzi, ale czy coś takiego działa?

StringBuilder sb = new StringBuilder(); 
Byte[] buf = new byte[8192]; 
Stream resStream = response.GetResponseStream(); 
string tmpString = null; 
int count = 0; 
do 
{ 
    count = resStream.Read(buf, 0, buf.Length); 
    if(count != 0) 
    { 
      tmpString = Encoding.ASCII.GetString(buf, 0, count); 
      sb.Append(tmpString); 
    } 
}while (count > 0); 
+4

Jest to niebezpieczne dla kodowań wielobajtowych (tzn. Nie ASCII), ponieważ nie ma gwarancji, że odczyty będą wyrównane do granic znaków. – spender

+2

@Chuck Nie możesz po prostu użyć ASCII, musisz dowiedzieć się, jakie kodowanie jest aktualnie używane, np. Za pomocą Content-Type, a następnie użyć go do "GetString" –

0

Craig, nie widząc strumień czytasz to trochę trudne do debugowania, ale może można zmienić ustawienia zmiennej licznika do tego:

count = resStream.Read(buf, 0, buf.Length-1); 

To trochę hack , ale jeśli ostatni odczyt cię zabije i nie zwróci żadnych danych, teoretycznie to pozwoli uniknąć problemu. Wciąż się zastanawiam, dlaczego to robi.

0

Miałem ten sam problem (tak znalazłem się tutaj :-). W końcu wyśledził to, że porwany strumień nie był prawidłowy - brakowało końcowego kawałka o zerowej długości. Wymyśliłem następujący kod, który obsługuje zarówno poprawne, jak i niepoprawne porcje strumieniowe.

using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 
{ 
    StringBuilder sb = new StringBuilder(); 

    try 
    { 
     while (!sr.EndOfStream) 
     { 
      sb.Append((char)sr.Read()); 
     } 
    } 
    catch (System.IO.IOException) 
    { } 

    string content = sb.ToString(); 
} 
+2

Casting bajtów na char jest niebezpieczny, ponieważ całkowicie ignoruje wielobajtowe kodowania. – spender

1

Pracuję nad podobnym problemem. Pliki .net HttpWebRequest i HttpWebRequest obsługują pliki cookie i automatycznie przekierowują, ale nie obsługują automatycznie treści podzielonej na treść odpowiedzi.

Jest tak prawdopodobnie dlatego, że porowata zawartość może zawierać więcej niż zwykłe dane (np. Nazwy kawałków, końcowe nagłówki).

Po prostu czytanie strumienia i ignorowanie wyjątku EOF nie będzie działać, ponieważ strumień zawiera więcej niż pożądana zawartość. Strumień będzie zawierał porcje, a każda porcja rozpoczyna się od deklaracji jego rozmiaru. Jeśli strumień jest po prostu odczytywany od początku do końca, ostateczne dane będą zawierać metadane porcji (a w przypadku, gdy jest to zawartość gzipowana, nie powiedzie się kontrola CRC podczas dekompresji).

Aby rozwiązać problem, należy ręcznie przeanalizować strumień, usuwając rozmiar porcji z każdej porcji (jak również ograniczniki CR LF), wykrywając ostatni fragment i zachowując tylko dane porcji. Prawdopodobnie jest gdzieś biblioteka, która to robi, jeszcze jej nie znalazłem.

Przydatne zasoby:

http://en.wikipedia.org/wiki/Chunked_transfer_encoding http://tools.ietf.org/html/rfc2616#section-3.6.1

Powiązane problemy