Может ли веб-служба вернуть поток?
Я пишу небольшое приложение, которое позволит людям загружать и загружать файлы мне. Я добавил веб-сервис для этого приложения, чтобы предоставить возможность загрузки/загрузки таким образом, но я не слишком уверен в том, насколько хорошо моя реализация будет справляться с большими файлами.
В настоящее время определения методов загрузки и загрузки выглядят так (написано с использованием 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 ГБ), то он попытается помещать всю эту информацию в память и разбивать мои сервисы.
Итак, мой вопрос: вместо этого можно вернуть какой-то поток? Я бы предположил, что это не будет ужасно независимым от ОС. Хотя я знаю теорию, лежащую в основе веб-сервисов, практическая сторона - это то, что мне все еще нужно получить немного информации.
Приветствия для любого ввода,
Ли
Ответы
Ответ 1
Stephen Denne имеет реализацию Metro, которая удовлетворяет вашим требованиям. Мой ответ приведен ниже, после краткого объяснения, почему это так.
Большинство реализаций веб-сервисов, которые построены с использованием HTTP в качестве протокола сообщений, соответствуют требованиям REST, поскольку они допускают только простые шаблоны send-receive и не более того. Это значительно улучшает взаимодействие, так как все различные платформы могут понять эту простую архитектуру (например, веб-сервис Java, говорящий с веб-службой .NET).
Если вы хотите сохранить это, вы можете предоставить chunking.
boolean uploadFile(String username, String password, String fileName, int currentChunk, int totalChunks, byte[] chunk);
Это потребует некоторой работы в тех случаях, когда вы не получите куски в правильном порядке (или вы можете просто потребовать, чтобы куски пришли в правильном порядке), но, вероятно, это будет довольно легко реализовать.
Ответ 2
Да, это возможно с Metro. См. Пример Large Attachments, который выглядит так, как будто он делает то, что вы хотите.
JAX-WS RI обеспечивает поддержку отправки и приема больших вложений потоковым способом.
- Используйте MTOM и DataHandler в модели программирования.
- Передача DataHandler в StreamingDataHandler и использование его методов.
- Убедитесь, что вы вызываете StreamingDataHandler.close(), а также закрываете поток StreamingDataHandler.readOnce().
- Включить HTTP-chunking на стороне клиента.
Ответ 3
Когда вы используете стандартизованный веб-сервис, отправитель и получатель полагаются на целостность отправки данных XML от одного к другому. Это означает, что запрос веб-службы и ответ только завершены при отправке последнего тега. Имея это в виду, веб-сервис нельзя рассматривать как поток.
Это логично, потому что стандартизированные веб-службы полагаются на http-протокол. Этот "без гражданства", скажет, что он работает как "открытое соединение... отправить запрос... получить данные... закрыть запрос". Во всяком случае, соединение будет закрыто. Так что что-то вроде потоковой передачи не предназначено для использования здесь. Или он слоями выше http (например, веб-сервисы).
Так жаль, но насколько я вижу, нет возможности для потоковой передачи в веб-сервисах. Еще хуже: в зависимости от реализации/конфигурации веб-службы байт [] - данные могут быть переведены на Base64, а не на CDATA-тег, и запрос может стать еще более раздутым.
P.S.: Да, как писали другие, возможно "чутье". Но это не поток, как таковой;-) - во всяком случае, это может вам помочь.
Ответ 4
Для WCF я думаю, что его можно определить члена в сообщении как поток и установить привязку соответствующим образом - я видел эту работу с wcf, говорящим с веб-службой Java.
Вам нужно установить transferMode = "StreamedResponse" в конфигурации httpTransport и использовать mtomMessageEncoding (необходимо использовать раздел настраиваемого связывания в конфиге).
Я думаю, что одно ограничение состоит в том, что вы можете иметь только один элемент тела сообщения, если хотите потокочет (какой смысл имеет смысл).
Ответ 5
Apache CXF поддерживает потоки отправки и получения.
Ответ 6
Мне не нравится разбивать его тем, кто думает, что потоковая веб-служба невозможна, но на самом деле все HTTP-запросы основаны на потоках. Каждый браузер, выполняющий GET на веб-сайт, основан на потоке. Каждый вызов веб-службы основан на потоке. Да все. Мы не замечаем этого на том уровне, где мы реализуем сервисы или страницы, потому что более низкие уровни архитектуры имеют дело с этим для вас - но это делается.
Вы когда-нибудь замечали в браузере, что иногда может потребоваться некоторое время, чтобы получить страницу - браузер просто держится, показывая песочные часы? Это связано с тем, что браузер ожидает поток.
Потоки - это причина, по которой mime/types должны быть отправлены до фактических данных - это всего лишь поток байтов в браузере, он не сможет идентифицировать фотографию, если вы не сказали ей, что это было первым, Кроме того, почему вы должны передать размер двоичного файла перед отправкой - браузер не сможет определить, где изображение остановится, и страница снова забирается.
Это всего лишь поток байтов для клиента. Если вы хотите доказать это для себя, просто удержите выходной поток в любой момент обработки запроса и закройте его(). Вы взорвете все. Браузер немедленно прекратит показ песочных часов и отобразит "не может найти" или "соединение reset на сервере" или какое-то другое такое сообщение.
То, что многие люди не знают, что весь этот материал основан на потоках, показывает, насколько много материала было наложено поверх него. Некоторые скажут слишком много вещей - я один из них.
Удачи и счастливого развития - расслабьте плечи!
Ответ 7
Один из способов сделать это - добавить метод uploadFileChunk (byte [] chunkData, int size, int offset, int totalSize) (или что-то в этом роде), который загружает части файла и серверы записывают его на диск.
Ответ 8
Имейте в виду, что запрос веб-службы в основном сводится к одному HTTP POST.
Если вы посмотрите на вывод файла .ASMX в .NET, он точно покажет вам, как будет выглядеть запрос и ответ POST.
Chunking, как упоминается @Guvante, будет самым близким к тому, что вы хотите.
Я предполагаю, что вы могли бы реализовать свой собственный код веб-клиента для обработки TCP/IP и потокового вещания в ваше приложение, но это было бы сложно сказать.
Ответ 9
Я думаю, что использование простого сервлета для этой задачи было бы намного проще, или есть какая-то причина, по которой вы не можете использовать сервлет?
Например, вы можете использовать Commons библиотеку с открытым исходным кодом.
Ответ 10
Библиотека RMIIO для Java обеспечивает передачу RemoteInputStream через RMI - нам нужен только RMI, хотя вы должны быть в состоянии адаптировать код для работы над другими типами RMI. Это может помочь вам, особенно если вы можете иметь небольшое приложение на стороне пользователя. Библиотека была разработана с целью ограничить размер данных, перемещаемых на сервер, чтобы избежать точно такого типа ситуации, который вы описываете, - эффективно атака DOS, заполняя RAM или диск.
В библиотеке RMIIO сторона сервера принимает решение о том, сколько данных он хочет вытащить, где с помощью HTTP PUT и POST клиент получает это решение, включая скорость, с которой он нажимает.
Ответ 11
Да, веб-сервис может выполнять потоковое вещание. Я создал веб-сервис с использованием Apache Axis2 и MTOM для поддержки рендеринга PDF-документов из XML. Поскольку результирующие файлы могут быть довольно большими, потоковая передача важна, потому что мы не хотим хранить все это в памяти. Взгляните на документацию Oracle на потоковое вложение SOAP.
В качестве альтернативы вы можете сделать это самостоятельно, а tomcat создаст заголовки Chunked. Это пример функции контроллера spring, которая передает потоки.
@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();
}
Ответ 12
На самом деле не так сложно "обрабатывать 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, поэтому в браузере может возникнуть ошибка, но на самом деле это все, что нужно.
Удача в вашем развитии!
Родни