Pergunta

Estou tendo problemas para ler uma resposta "fragmentada" ao usar um StreamReader para ler o fluxo retornado por GetResponseStream() de um HttpWebResponse:

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

Quando o reader.ReadToEnd() método é chamado, estou recebendo o seguinte System.IO.IOException: Não é possível ler dados da conexão de transporte:A conexão foi fechada.

O código acima funciona bem quando o servidor retorna uma resposta "não fragmentada".

A única maneira de fazê-lo funcionar é usar HTTP/1.0 para a solicitação inicial (em vez de HTTP/1.1, o padrão), mas isso parece uma solução alternativa esfarrapada.

Alguma ideia?


@Mandril

Sua solução funciona muito bem.Ele ainda lança o mesmo IOExecception no último Read().Mas depois de inspecionar o conteúdo do StringBuilder parece que todos os dados foram recebidos.Então, talvez eu só precise agrupar Read() em um try-catch e engolir o "erro".

Foi útil?

Solução

Ainda não tentei fazer isso com uma resposta "fragmentada", mas algo assim funcionaria?

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

Outras dicas

Estou trabalhando em um problema semelhante.O .net HttpWebRequest e o HttpWebRequest lidam com cookies e redirecionamentos automaticamente, mas não lidam automaticamente com conteúdo fragmentado no corpo da resposta.

Talvez isso ocorra porque o conteúdo fragmentado pode conter mais do que dados simples (ou seja:nomes de blocos, cabeçalhos finais).

Simplesmente ler o stream e ignorar a exceção EOF não funcionará, pois o stream contém mais do que o conteúdo desejado.O fluxo conterá pedaços e cada pedaço começa declarando seu tamanho.Se o fluxo for simplesmente lido do início ao fim, os dados finais conterão os metadados do bloco (e no caso de conteúdo compactado em gzip, a verificação CRC falhará ao descompactar).

Para resolver o problema é necessário analisar manualmente o fluxo, removendo o tamanho do pedaço de cada pedaço (bem como os delimitadores CR LF), detectando o pedaço final e mantendo apenas os dados do pedaço.Provavelmente existe uma biblioteca em algum lugar que faz isso, ainda não a encontrei.

Recursos úteis:

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

Craig, sem ver o fluxo que você está lendo é um pouco difícil de depurar, mas TALVEZ você possa alterar a configuração da variável de contagem para isto:

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

É um pouco complicado, mas se a última leitura estiver matando você e não estiver retornando nenhum dado, teoricamente isso evitará o problema.Ainda me pergunto por que o stream está fazendo isso.

Eu tive o mesmo problema (e foi assim que acabei aqui :-).Eventualmente, descobri que o fluxo em pedaços não era válido - o pedaço final de comprimento zero estava faltando.Eu criei o código a seguir, que lida com fluxos em partes válidos e inválidos.

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();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top