Может ли веб-сервис вернуть поток? - PullRequest
28 голосов
/ 25 сентября 2008

Я написал небольшое приложение, которое позволит людям загружать и скачивать мне файлы. Я добавил веб-сервис к этому приложению, чтобы таким образом предоставлять функции загрузки / выгрузки, но я не очень уверен, насколько хорошо моя реализация справится с большими файлами.

На данный момент определения методов выгрузки и загрузки выглядят так (написано с использованием Apache CXF):

boolean uploadFile(@WebParam(name = "username") String username,
    @WebParam(name = "password") String password,
    @WebParam(name = "filename") String filename,
    @WebParam(name = "fileContents") byte[] fileContents)
    throws UploadException, LoginException;

byte[] downloadFile(@WebParam(name = "username") String username,
    @WebParam(name = "password") String password,
    @WebParam(name = "filename") String filename) throws DownloadException,
    LoginException;

Таким образом, файл загружается и загружается как байтовый массив. Но если у меня есть файл какого-то глупого размера (например, 1 ГБ), он наверняка попытается поместить всю эту информацию в память и завершит работу моего сервиса.

Итак, мой вопрос - можно ли вместо этого вернуть какой-нибудь поток? Я бы предположил, что это не будет ужасно независимым от ОС, хотя. Хотя я знаю теорию веб-сервисов, практическая сторона - это то, что мне все еще нужно, чтобы собрать немного информации.

Приветствия для любого входа, Lee

Ответы [ 12 ]

14 голосов
/ 25 сентября 2008

Да, это возможно с метро. См. Пример Large Attachments , который выглядит так, как будто он делает то, что вы хотите.

JAX-WS RI обеспечивает поддержку для отправки и получения больших вложений потоковым способом.

  • Использование MTOM и DataHandler в модели программирования.
  • Приведите DataHandler к StreamingDataHandler и используйте его методы.
  • Убедитесь, что вы вызываете StreamingDataHandler.close (), а также закрываете поток StreamingDataHandler.readOnce ().
  • Включить HTTP-чанкинг на стороне клиента.
6 голосов
/ 25 сентября 2008

Стивен Денн имеет реализацию Metro, которая отвечает вашим требованиям. Мой ответ приведен ниже после краткого объяснения, почему это так.

Большинство реализаций веб-служб, которые построены с использованием HTTP в качестве протокола сообщений, соответствуют REST, поскольку они допускают только простые шаблоны отправки и получения и ничего более. Это значительно улучшает взаимодействие, поскольку все различные платформы могут понимать эту простую архитектуру (например, веб-сервис Java, взаимодействующий с веб-сервисом .NET).

Если вы хотите сохранить это, вы можете предоставить порцию.

boolean uploadFile(String username, String password, String fileName, int currentChunk, int totalChunks, byte[] chunk);

Это потребует некоторых усилий в тех случаях, когда вы не получите чанки в правильном порядке (или вы можете просто потребовать, чтобы чанки пришли в правильном порядке), но это, вероятно, будет довольно легко реализовать.

3 голосов
/ 25 сентября 2008

Когда вы используете стандартизированный веб-сервис, отправитель и получатель полагаются на целостность данных XML, передаваемых от одного к другому. Это означает, что запрос и ответ веб-службы завершаются только после отправки последнего тега. Учитывая это, веб-сервис не может рассматриваться как поток.

Это логично, поскольку стандартизированные веб-сервисы используют протокол http. Тот, кто "не имеет состояния", скажет, что работает как "открытое соединение ... отправить запрос ... получить данные ... закрыть запрос". В конце концов, соединение будет закрыто. Поэтому что-то вроде потоковой передачи здесь не предназначено для использования. Или он находится выше http (как веб-сервисы).

Извините, но, насколько я вижу, нет возможности для потоковой передачи в веб-сервисах. Еще хуже: в зависимости от реализации / конфигурации веб-сервиса, byte [] - данные могут быть переведены в Base64, а не в CDATA-тег, и запрос может стать еще более раздутым.

П.С .: Да, как писали другие, "чукаясь" возможно. Но это не потоковое вещание как таковое ;-) - в любом случае, оно может вам помочь.

1 голос
/ 14 марта 2012

Я не хочу говорить об этом тем, кто считает, что потоковый веб-сервис невозможен, но на самом деле все http-запросы основаны на потоке. Каждый браузер, выполняющий GET для веб-сайта, основан на потоке. Каждый вызов веб-сервиса основан на потоке. Да все. Мы не замечаем этого на уровне, на котором мы реализуем сервисы или страницы, потому что более низкие уровни архитектуры справляются с этим для вас - но это делается.

Вы когда-нибудь замечали в браузере, что иногда получение страницы может занять некоторое время - браузер просто продолжает показывать песочные часы? Это потому, что браузер ожидает в потоке.

Потоки - это причина, по которой mime / типы должны отправляться перед фактическими данными - это всего лишь байтовый поток в браузер, он не сможет идентифицировать фотографию, если вы не скажете ей, какой она была первой , Именно поэтому вы должны передать размер двоичного файла перед отправкой - браузер не сможет определить, где останавливается изображение, и страница снова начинает работать.

Это всего лишь поток байтов для клиента. Если вы хотите доказать это для себя, просто возьмите поток вывода в любой точке обработки запроса и закройте его (). Вы взорвете все. Браузер немедленно прекратит показывать песочные часы и отобразит сообщение «не удается найти» или «сброс соединения на сервере» или другое подобное сообщение.

То, что многие люди не знают, что весь этот материал основан на потоке, показывает, сколько всего материала было наложено поверх него. Кто-то скажет слишком много всего - я один из них.

Удачи и счастливого развития - расслабь плечи!

1 голос
/ 23 декабря 2009

Apache CXF поддерживает отправку и получение потоков.

1 голос
/ 25 сентября 2008

Для WCF я считаю возможным определить элемент сообщения как поток и правильно установить привязку - я видел эту работу с wcf, разговаривающим с веб-сервисом Java.

Вам необходимо установить значение TransferMode = "StreamedResponse" в конфигурации httpTransport и использовать mtomMessageEncoding (необходимо использовать пользовательский раздел привязки в конфигурации).

Я думаю, что одно ограничение заключается в том, что вы можете иметь только один элемент тела сообщения, если хотите транслировать (что имеет смысл).

0 голосов
/ 02 апреля 2012

На самом деле не так уж сложно «обрабатывать TCP / IP и передавать данные в ваше приложение». Попробуйте это ...

class MyServlet extends HttpServlet
{
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    {
        response.getOutputStream().println("Hello World!");
    }
}

И это все, что нужно сделать. В приведенном выше коде вы ответили на запрос HTTP GET, отправленный из браузера, и вернули этому браузеру текст «Hello World!».

Имейте в виду, что "Hello World!" HTML-код недействителен, поэтому в браузере может возникнуть ошибка, но на самом деле это все, что нужно.

Удачи в вашем развитии!

Родня

0 голосов
/ 08 августа 2011

Да, веб-сервис может выполнять потоковую передачу. Я создал веб-сервис, используя Apache Axis2 и MTOM для поддержки рендеринга PDF-документов из XML. Поскольку результирующие файлы могут быть довольно большими, потоковая передача важна, потому что мы не хотим хранить все это в памяти. Посмотрите документацию Oracle по потоковым вложениям SOAP.

Кроме того, вы можете сделать это самостоятельно, и tomcat создаст Chunked-заголовки. Это пример функции пружинного контроллера, которая выполняет потоковую передачу.

 @RequestMapping(value = "/stream")
        public void hellostreamer(HttpServletRequest request, HttpServletResponse response) throws CopyStreamException, IOException  
{

            response.setContentType("text/xml");
            OutputStreamWriter writer = new OutputStreamWriter (response.getOutputStream());
            writer.write("this is streaming");
            writer.close();

    }
0 голосов
/ 25 сентября 2008

Библиотека RMIIO для Java обеспечивает передачу RemoteInputStream через RMI - нам нужен только RMI, хотя вы должны быть в состоянии адаптировать код для работы с другими типами RMI. Это может помочь вам, особенно если у вас есть небольшое приложение на стороне пользователя. Библиотека была разработана специально для того, чтобы иметь возможность ограничить размер данных, передаваемых на сервер, чтобы избежать именно того типа ситуации, который вы описываете - фактически атаки DOS, заполнив оперативную память или диск.

С библиотекой RMIIO серверная сторона решает, сколько данных она хочет извлечь, где с помощью HTTP PUT и POSTs клиент получает это решение, включая скорость, с которой он выдвигается.

0 голосов
/ 25 сентября 2008

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

Например, вы можете использовать библиотеку с открытым исходным кодом Commons .

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