【问题标题】:HTTP Headers for Unknown Content-Length未知内容长度的 HTTP 标头
【发布时间】:2010-03-07 04:33:24
【问题描述】:

我目前正在尝试在转码过程后将内容流式传输到网络。这通常可以通过将二进制文件写入我的 Web 流来正常工作,但是某些浏览器(特别是 IE7、IE8)不喜欢在 HTTP 标头中没有定义 Content-Length。我相信“有效”的标题应该有这个设置。

当您的 Content-Length 未知时,将内容流式传输到网络的正确方法是什么?转码过程可能需要一段时间,所以我想在它完成后开始流式传输。

【问题讨论】:

    标签: .net http binary streaming http-headers


    【解决方案1】:

    尝试将它们与Transfer-Encoding: chunked 一起发送。更多详情在wikipedia

    更新根据 cmets,下面是 Java 中“ChunkedOutputStream”的示例:

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

    ...基本上可以用作:

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

    您在源代码中看到,每个数据块都存在一个标头,该标头代表十六进制数据的长度、一个 CRLF、实际数据和一个 CRLF。流的结尾由表示 0 长度和两个 CRLF 的标头表示。

    注意:尽管有示例,但您实际上不需要在基于 JSP/Servlet 的 Web 应用程序中需要它。每当响应中没有设置内容长度时,webcontainer 会自动以块的形式传输它们。

    【讨论】:

    • 我尝试使用块,Firefox 收到它们时会锁定。我正在传输二进制数据,是否必须将其转换为十六进制才能使用块?是否有任何可用的 .NET 库?
    • 不,您不需要转换。如果您不预先指定内容长度,我希望 .NET 会自动处理此问题。
    • 单击chunked 后面的链接和维基百科链接,了解它的外观。我不做 .NET,所以我不能给出太多,但我可以给出一个基于 Java 的示例,以扩展 OutputStream 的风格。如果您想看,请告诉我。
    • 如果你能提供的话,我会举 Java 的例子。我想我可以对 .NET 做一点翻译。我特别想知道我是否可以发送二进制数据。到目前为止,我只看到了十六进制,总的来说,我很少看到分块传输如何工作的示例。
    • 在 Java servlet 中,您只需发送数据而不设置内容长度。这将切换到分块编码。是的,二进制有效。
    【解决方案2】:

    作为 BalusC 优秀帖子的后续,这里是我在 C# 中使用的代码。在从进程的 STDOUT 接收数据后,我将数据直接手动分块到 HTTP 输出流。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-23
      • 2012-04-01
      • 1970-01-01
      • 2012-12-02
      • 1970-01-01
      • 2022-01-28
      • 2012-05-26
      • 2014-04-30
      相关资源
      最近更新 更多