Копирование блоков InputStream с помощью HTTP-клиента Jetty с использованием InputStreamResponseListener - PullRequest
0 голосов
/ 23 мая 2018

Я использую HTTP-клиент Jetty 9.4.8 и хочу записать поток входящих данных в файл.В настоящее время я использую InputStreamResponseListener и IOUtils.copy (..) для записи в FileOutputStream.Я также пробовал Files.copy ().

InputStreamResponseListener streamResponseListener = new InputStreamResponseListener();

request.send(streamResponseListener);

if(streamResponseListener.get(5, TimeUnit.MINUTES).getStatus() == 200) {
    OutputStream outputStream = null;
    try {
        TMP_FILE.toFile().createNewFile();
        outputStream = new FileOutputStream(TMP_FILE.toFile());
        IOUtils.copy(inputStream, outputStream);
    } catch(IOException e) {
        this.getLogService().log(..)
    } finally {
        IOUtils.closeQuietly(inputStream);
        IOUtils.closeQuietly(outputStream);
    }

    // NOT REACHED IN CASE InputStream is BLOCKED FOR SOME REASON
}

Однако методы копирования, похоже, блокируются после получения всех байтов.Почему это могло произойти и как этого избежать?

Заголовки запрошенного содержимого HTTP:

Date: Wed, 23 May 2018 16:46:06 GMT
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=".."
Content-Length: 613970044
Server: Jetty(9.4.8.v20171121)

IOUtils из Apache Commons IO Version 2.4

1 Ответ

0 голосов
/ 23 мая 2018

Вот рабочий пример вашей кодовой базы, использующей только Java и Jetty.

Это запрос контента с сервера, который, как известно, соответствует спецификации HTTP.

package demo.jettyclient;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.util.InputStreamResponseListener;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.ssl.SslContextFactory;

public class DownloadUrl
{
    public static void main(String[] args) throws Exception
    {
        String uriString = "https://upload.wikimedia.org/wikipedia/en/a/a1/Jetty_logo.png?download";

        if (args.length >= 1)
            uriString = args[0];

        URI srcUri = URI.create(uriString);

        SslContextFactory ssl = new SslContextFactory(true);

        HttpClient client = new HttpClient(ssl);
        try
        {
            client.start();

            Request request = client.newRequest(srcUri);

            System.out.printf("Using HttpClient v%s%n", getHttpClientVersion());
            System.out.printf("Requesting: %s%n", srcUri);
            InputStreamResponseListener streamResponseListener = new InputStreamResponseListener();
            request.send(streamResponseListener);
            Response response = streamResponseListener.get(5, TimeUnit.SECONDS);

            if (response.getStatus() != HttpStatus.OK_200)
            {
                throw new IOException(
                        String.format("Failed to GET URI [%d %s]: %s",
                                response.getStatus(),
                                response.getReason(),
                                srcUri));
            }

            Path tmpFile = Files.createTempFile("tmp", ".dl");

            try (InputStream inputStream = streamResponseListener.getInputStream();
                 OutputStream outputStream = Files.newOutputStream(tmpFile))
            {
                IO.copy(inputStream, outputStream);
            }

            System.out.printf("Downloaded %s%n", srcUri);
            System.out.printf("Destination: %s (%,d bytes)%n", tmpFile.toString(), Files.size(tmpFile));
        }
        finally
        {
            client.stop();
        }
    }

    private static String getHttpClientVersion()
    {
        ClassLoader cl = HttpClient.class.getClassLoader();

        // Attempt to use maven pom properties first
        String pomResource = "/META-INF/maven/org/eclipse/jetty/jetty-client/pom.properties";
        URL url = cl.getResource(pomResource);
        if (url != null)
        {
            try (InputStream in = url.openStream())
            {
                Properties props = new Properties();
                props.load(in);
                String version = props.getProperty("version");
                if (StringUtil.isNotBlank(version))
                    return version;
            }
            catch (IOException ignore)
            {
            }
        }

        // Attempt to use META-INF/MANIFEST.MF
        String version = HttpClient.class.getPackage().getImplementationVersion();
        if (StringUtil.isNotBlank(version))
            return version;

        return "<unknown>";
    }
}

КогдаВыполните, это приводит к ...

2018-05-23 10:52:08.401:INFO::main: Logging initialized @325ms to org.eclipse.jetty.util.log.StdErrLog
Using HttpClient v9.4.9.v20180320
Requesting: https://upload.wikimedia.org/wikipedia/en/a/a1/Jetty_logo.png?download
Downloaded https://upload.wikimedia.org/wikipedia/en/a/a1/Jetty_logo.png?download
Destination: C:\Users\joakim\AppData\Local\Temp\tmp2166600286896937563.dl (11,604 bytes)

Process finished with exit code 0

Вероятно, проблема связана с одним (или более) из следующего:

  1. С вашим сервером что-то не так, несоответствие спецификации HTTP.
  2. Обмен HTTP еще не завершен (с точки зрения протокола).Захватите трафик и проверьте поведение.
  3. Используемая вами библиотека IOUtil (вы не сказали, какая из них) содержит ошибку.

Тот факт, что wget (или curl)скорее всего, потому что они не строго соответствуют Content-Length (согласно рекомендациям в RFC7230) и будут отображать / загружать весь полученный контент до тех пор, пока физическое соединение не завершится / не отключится.В то время как протокол HTTP / 1.1 имеет постоянство соединения и строгие правила, когда заканчивается содержимое запроса (и ответа).

...