2010-03-07 40 views
20

Actualmente estoy tratando de transmitir contenido a la web después de un proceso de transcodificación. Por lo general, esto funciona bien escribiendo binariamente en mi secuencia web, pero a algunos navegadores (específicamente IE7, IE8) no les gusta no tener el Contenido-Longitud definido en el encabezado HTTP. Creo que se supone que los encabezados "válidos" tienen este conjunto.Cabeceras HTTP para longitud desconocida de contenido

¿Cuál es la forma correcta de transmitir contenido a la web cuando tiene una longitud desconocida de contenido? El proceso de transcodificación puede llevar un tiempo, así que quiero comenzar a transmitirlo a medida que se completa.

Respuesta

18

Intente enviarlos en trozos junto con Transfer-Encoding:chunked. Más detalles en wikipedia.

actualización según los comentarios, he aquí un ejemplo de cómo un "ChunkedOutputStream" en Java puede verse como:

package com.stackoverflow.q2395192; 

import java.io.IOException; 
import java.io.OutputStream; 

public class ChunkedOutputStream extends OutputStream { 

    private static final byte[] CRLF = "\r\n".getBytes(); 
    private OutputStream output = null; 

    public ChunkedOutputStream(OutputStream output) { 
     this.output = output; 
    } 

    @Override 
    public void write(int i) throws IOException { 
     write(new byte[] { (byte) i }, 0, 1); 
    } 

    @Override 
    public void write(byte[] b, int offset, int length) throws IOException { 
     writeHeader(length); 
     output.write(CRLF, 0, CRLF.length); 
     output.write(b, offset, length); 
     output.write(CRLF, 0, CRLF.length); 
    } 

    @Override 
    public void flush() throws IOException { 
     output.flush(); 
    } 

    @Override 
    public void close() throws IOException { 
     writeHeader(0); 
     output.write(CRLF, 0, CRLF.length); 
     output.write(CRLF, 0, CRLF.length); 
     output.close(); 
    } 

    private void writeHeader(int length) throws IOException { 
     byte[] header = Integer.toHexString(length).getBytes(); 
     output.write(header, 0, header.length); 
    } 

} 

... que básicamente se puede utilizar como:

OutputStream output = new ChunkedOutputStream(response.getOutputStream()); 
output.write(....); 

Usted ve en la fuente, cada pedazo de datos existe de un encabezado que representa la longitud de los datos en hexadecimal, un CRLF, los datos reales y un CRLF. El final de la secuencia está representado por un encabezado que indica una longitud 0 y dos CRLF.

Nota: a pesar del ejemplo, que realmente hacen no lo necesitan en una aplicación web basada en JSP/Servlet. Cuando la longitud del contenido no se establece en una respuesta, el contenedor web los transferirá automáticamente en fragmentos.

+0

He intentado usar trozos, y Firefox se bloqueaba al recibirlos. Estoy transfiriendo datos binarios, ¿tengo que convertirlos a hexadecimal para usar fragmentos? ¿Hay alguna biblioteca .NET disponible para esto? – jocull

+1

No, no es necesario convertir. Y esperaría que .NET maneje esto automáticamente si no especifica la longitud del contenido por adelantado. –

+0

Haga clic en el enlace detrás de 'chunked' y en el enlace de wikipedia para tener una idea de cómo debería ser. No hago .NET, así que no puedo dar mucho, pero puedo dar un ejemplo basado en Java en el sabor de un 'OutputStream' extendido. Hazle saber si te gustaría verlo. – BalusC

2

Como seguimiento de la excelente publicación de BalusC, aquí está el código que estoy usando en C#. Estoy fragmentando datos manualmente en una secuencia de salida HTTP, después de recibir datos de STDOUT en un proceso.

int buffSize = 16384; 
byte[] buffer = new byte[buffSize]; 
byte[] hexBuff; 
byte[] CRLF = Encoding.UTF8.GetBytes("\r\n"); 

br = new BinaryReader(transcoder.StandardOutput.BaseStream); 

//Begin chunking... 
int ret = 0; 
while (!transcoder.HasExited && (ret = br.Read(buffer, 0, buffSize)) > 0) 
{ 
    //Write hex length... 
    hexBuff = Encoding.UTF8.GetBytes(ret.ToString("X")); 
    e.Context.Stream.Write(hexBuff, 0, hexBuff.Length); 

    //Write CRLF... 
    e.Context.Stream.Write(CRLF, 0, CRLF.Length); 

    //Write byte content... 
    e.Context.Stream.Write(buffer, 0, ret); 

    //Write CRLF... 
    e.Context.Stream.Write(CRLF, 0, CRLF.Length); 
} 
//End chunking... 
//Write hex length... 
hexBuff = Encoding.UTF8.GetBytes(0.ToString("X")); 
e.Context.Stream.Write(hexBuff, 0, hexBuff.Length); 
+0

Buen trabajo, me alegro de que te haya ayudado. – BalusC

Cuestiones relacionadas