2011-10-21 61 views
5

基本上我的響應報頭包含 如何在java servlet中的分塊響應中發送Http預告片/頁腳?

傳輸編碼

=分塊,

拖車=一些預告片我想發說,例如「SomeTrailer」]

一旦我完成了將數據寫入到Servlet outputstream,我正在編寫預告片 「SomeTrailer:[value]」,但是這不會被httpclient正確解析。 httpclient將整個輸入流(包括預告片)視爲單個 塊。 我也試過在數據寫入輸出流但沒有成功後在響應頭中寫入預告片。

請幫

我還沒有發現有這方面的良好來源。

+1

這是客戶真正需要的嗎? 「TE」和「Trailer」很少使用,我從來沒有在真實世界的代碼中看到它。 servlet API具有對分塊響應的內置支持(甚至更多,當您不設置響應的內容長度時,它會默認發送)。但它沒有內置的分塊響應預告片支持。作爲替代,您可以將所需的預告片的值設置爲自定義響應標頭(僅當該值與US-ASCII兼容且不超過某個最大長度時)。 – BalusC

+0

@BalusC我的用例是服務器發送無限數據流並且不知道它的內容長度。服務器代碼也正在計算校驗和,以便它可以將其作爲預告片發送,客戶端將使用該預告片來驗證數據。 –

回答

3

我最終爲此寫了一個簡單的單線程網絡服務器。原來這很容易。服務器非常簡單。代碼雖然有點粗糙,但主要思想在那裏。

它做了什麼它將filecontents作爲第一個塊和文件的校驗和作爲頁腳。

import java.io.BufferedReader; 
import java.io.DataOutputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.InputStreamReader; 
import java.net.ServerSocket; 
import java.net.Socket; 

import org.apache.commons.codec.digest.DigestUtils; 
import org.apache.commons.io.IOUtils; 
import org.apache.log4j.Logger; 

public class ChunkedResponseServer implements Runnable { 
    private static final Logger LOGGER = Logger.getLogger(ChunkedResponseServer.class); 

    // Space ' ' 
    static final byte SP = 32; 
    // Tab ' ' 
    static final byte HT = 9; 
    // Carriage return 
    static final byte CR = 13; 
    // Line feed character 
    static final byte LF = 10; 

    final int port; 

    private volatile boolean cancelled = false; 

    public ChunkedResponseServer(int port) { 
    LOGGER.info("Chunked response server running on port " + port); 
    this.port = port; 
    } 

    @Override 
    public void run() { 
    ServerSocket serverSocket = null; 
    try { 
     serverSocket = new ServerSocket(port); 
     while (!cancelled) { 
     final Socket connectionSocket = serverSocket.accept(); 
     handle(connectionSocket); 
     } 
    } catch (final IOException e) { 
     throw new RuntimeException(e); 
    } 
    } 

    public void cancel() { 
    LOGGER.info("Shutting down Chunked response Server"); 
    cancelled = true; 
    } 

    private void handle(Socket socket) throws IOException { 
    BufferedReader input = null; 
    DataOutputStream output = null; 
    try { 
     input = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
     output = new DataOutputStream(socket.getOutputStream()); 

     addHeaders(output); 
     addCRLR(output); 

     final String filename = readFilename(input); 
     final byte[] content = readContent(filename); 
     addContentAsChunk(output, content); 

     final String checksum = DigestUtils.md5Hex(content); 
     addLastChunkAndChecksumFooter(output, checksum); 
     addCRLR(output); 

    } finally { 
     IOUtils.closeQuietly(input); 
     IOUtils.closeQuietly(output); 
    } 
    } 

    private void addLastChunkAndChecksumFooter(DataOutputStream output, String checksum) throws IOException { 
    output.writeBytes("0"); 
    addCRLR(output); 
    output.writeBytes("checksum: " + checksum); 
    addCRLR(output); 
    } 

    private void addContentAsChunk(DataOutputStream output, byte[] content) throws IOException { 
    output.writeBytes(Integer.toHexString(content.length)); 
    addCRLR(output); 
    output.write(content); 
    addCRLR(output); 
    } 

    private void addCRLR(DataOutputStream output) throws IOException { 
    output.writeByte(CR); 
    output.writeByte(LF); 
    } 

    private void addHeaders(DataOutputStream output) throws IOException { 
    output.writeBytes("HTTP/1.1 200 OK"); 
    addCRLR(output); 
    output.writeBytes("Content-type: text/plain"); 
    addCRLR(output); 
    output.writeBytes("Transfer-encoding: chunked"); 
    addCRLR(output); 
    output.writeBytes("Trailer: checksum"); 
    addCRLR(output); 
    } 

    private String readFilename(BufferedReader input) throws IOException { 
    final String initialLine = input.readLine(); 
    final String filePath = initialLine.split(" ")[1]; 
    final String[] components = filePath.split("/"); 
    return components[components.length - 1]; 
    } 

    private byte[] readContent(String filename) throws IOException { 
    final InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename); 
    return IOUtils.toByteArray(in); 
    } 
} 
相關問題