Использование GZIPOutputStream для отправки сжатого чанка в Java - PullRequest
0 голосов
/ 02 мая 2019

Я пытаюсь отправить сжатый HTML-файл через Java-сокет, но браузер отображает пустой HTML-файл.

Дело в том, что, когда я пытаюсь отправить несжатый HTML-файл, все работает найти (да, яизмените заголовки HTTP соответственно).

private void sendResponse(String headers, String body) throws IOException
{   
    BufferedOutputStream output = new BufferedOutputStream(
        this.SOCKET.getOutputStream());
    byte[] byteBody = null;

    // GZIP compression
    if(body != null && this.encoding.contains("gzip"))
    {
        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
        zipStream.write(body.getBytes(this.charset));
        zipStream.flush();
        byteBody = byteStream.toByteArray();
        byteStream.flush();
        byteStream.close();
        zipStream.close();
    }
    else
        byteBody = body.getBytes(this.charset);

    // Sending response
    byte[] msg1 = (Integer.toHexString(byteBody.length) + "\r\n")
        .getBytes(this.charset);
    byte[] msg2 = byteBody;
    byte[] msg3 = ("\r\n" + "0").getBytes(this.charset);

    output.write(headers.getBytes(this.charset));
    output.write(msg1);
    output.write(msg2);
    output.write(msg3);
    output.flush();
    output.close();
}

В основном заголовки содержит заголовки HTTP и тело HTML-файл.Остальное кажется самоочевидным.Что может вызвать такое поведение?

РЕДАКТИРОВАТЬ: заголовок создается следующим образом:

    headers = "HTTP/1.1 200 OK\r\n";
    headers += "Date: " + WebServer.getServerTime(Calendar.getInstance()) + "\r\n";
    headers += "Content-Type: text/html; charset=" + this.charset + "\r\n";
    headers += "Set-Cookie: sessionID=" + newCookie + "; Max-Age=600\r\n";
    headers += "Connection: close \r\n";
    if(this.encoding.contains("gzip"))
        headers += "Content-Encoding: gzip\r\n";
    headers += "Transfer-Encoding: chunked \r\n";
    headers += "\r\n";

Ответы [ 2 ]

0 голосов
/ 02 мая 2019

Проблема в том, что GZIPOutputStream не завершено, пока не будет вызван метод finish().

Он вызывается автоматически, когда вы close() поток.

Поскольку вы звоните byteStream.toByteArray() до того, как произойдет, вы не получите полные данные.

Кроме того, вам не нужночтобы позвонить flush(), поскольку это также выполняется автоматически при вызове close().А закрытие GZIPOutputStream автоматически закрывает базовый поток (ы) (то есть ByteArrayOutputStream).

Итак, ваш код должен быть:

ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
GZIPOutputStream zipStream = new GZIPOutputStream(byteStream);
zipStream.write(body.getBytes(this.charset));
zipStream.close();
byteBody = byteStream.toByteArray();
0 голосов
/ 02 мая 2019

Простой тестовый класс должен показать вам, где проблема:

import java.io.ByteArrayOutputStream;
import java.util.zip.GZIPOutputStream;

public class GZipTest {

    public final static void main(String[] args) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        GZIPOutputStream gzos = new GZIPOutputStream(baos);

        gzos.write("some data".getBytes());
        System.out.println("baos before gzip flush: " + baos.size());
        gzos.flush();
        System.out.println("baos after gzip flush: " + baos.size());
        gzos.close();
        System.out.println("baos after gzip close: " + baos.size());
    }
}

Это приводит к следующему выводу:

baos before gzip flush: 10
baos after gzip flush: 10
baos after gzip close: 29

Вы закрываете GZIPOutputStream после сборкиданные тела, поэтому браузер получает неполные GZIP-данные и поэтому не может распаковать их.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...