Web服务可以返回流吗?

时间:2008-09-25 10:55:38

标签: java web-services cxf

我一直在写一个让人们上传的小应用程序。下载文件给我。我已经为这个应用程序添加了一个Web服务,以提供上传/下载功能,但我不太确定我的实现将如何处理大文件。

目前上传和放大的定义下载方法看起来像这样(使用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;

因此文件作为字节数组上传和下载。但是,如果我有一个愚蠢的大小的文件(例如1GB),这肯定会尝试将所有信息放入内存并使我的服务崩溃。

所以我的问题是 - 是否有可能返回某种流?我想这不会是非常独立的操作系统。虽然我知道Web服务背后的理论,但实际的一面是我还需要了解一些信息。

为任何输入干杯, 利

12 个答案:

答案 0 :(得分:14)

是的,可以使用Metro。请参阅Large Attachments示例,该示例看起来就像您想要的那样。

  

JAX-WS RI支持以流方式发送和接收大型附件。

     
      
  • 在编程模型中使用MTOM和DataHandler。
  •   
  • 将DataHandler转换为StreamingDataHandler并使用其方法。
  •   
  • 确保调用StreamingDataHandler.close()并关闭StreamingDataHandler.readOnce()流。
  •   
  • 在客户端启用HTTP分块。
  •   

答案 1 :(得分:6)

Stephen Denne有一个满足您要求的Metro实施。在简短的探讨之后,我的答案将在下面提供。为什么会这样。

使用HTTP作为消息协议构建的大多数Web服务实现都符合REST,因为它们只允许简单的发送 - 接收模式,仅此而已。这极大地提高了互操作性,因为所有各种平台都可以理解这种简单的体系结构(例如,与Web Web服务交谈的Java Web服务)。

如果你想保持这个,你可以提供分块。

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

如果你没有按照正确的顺序获得块,这需要一些步法(或者你可以只需要按正确的顺序排列块),但它可能很容易实现。

答案 2 :(得分:3)

当您使用标准化Web服务时,发件人和收件人确实依赖于从一个发送到另一个的XML数据的完整性。这意味着仅在发送最后一个标记时才完成Web服务请求和应答。考虑到这一点,不能将Web服务视为流。

这是合乎逻辑的,因为标准化的Web服务确实依赖于http协议。那个是“无国籍”,会说它的工作方式就像“打开连接......发送请求......接收数据......关闭请求”。无论如何,连接将在最后关闭。所以像流媒体这样的东西不打算在这里使用。或者他在http之上(如网络服务)。

很抱歉,但据我所知,网络服务无法进行流式传输。更糟糕的是:取决于Web服务的实现/配置,byte [] - 数据可能会被转换为Base64而不是CDATA标签,并且请求可能会变得更加膨胀。

P.S。:Yup,正如其他人写的那样,“chuinking”是可能的。但这不是流媒体;-) - 无论如何,它可能对你有帮助。

答案 3 :(得分:1)

对于WCF,我认为可以将消息上的成员定义为流并适当地设置绑定 - 我已经看到这项工作与wcf谈论Java Web服务。

您需要在httpTransport配置中设置transferMode =“StreamedResponse”并使用mtomMessageEncoding(需要在配置中使用自定义绑定部分)。

我认为一个限制是,如果您想要流式传输(哪种有意义),您只能拥有一个邮件正文成员。

答案 4 :(得分:1)

Apache CXF支持发送和接收流。

答案 5 :(得分:1)

我讨厌将其分解为那些认为无法使用流式网络服务的人,但实际上,所有的http请求都是基于流的。每个对网站进行GET的浏览器都是基于流的。每次调用Web服务都是基于流的。是的,全部。我们在实现服务或页面的层面上没有注意到这一点,因为较低级别的架构正在为您处理这个问题 - 但它正在完成。

你有没有注意到在浏览器中有时需要一段时间来获取一个页面 - 浏览器只是不停地显示沙漏?那是因为浏览器正在等待流。

流是mime /类型必须在实际数据之前发送的原因 - 它只是浏览器的字节流,如果你没有告诉它是什么,它将无法识别照片。这也是为什么你必须在发送之前传递二进制文件的大小 - 浏览器将无法分辨图像停止的位置并且页面再次被拾取。

这只是客户端的字节流。如果你想自己证明这一点,只需在处理请求的任何时候保持输出流并关闭()它。你会炸毁一切。浏览器将立即停止显示沙漏,并将显示“无法找到”或“在服务器上重置连接”或其他此类消息。

很多人都不知道所有这些东西都是基于流的节目,只是在它上面分层了多少东西。有些人会说太多东西 - 我就是其中之一。

祝你好运,快乐发展 - 放松肩膀!

答案 6 :(得分:0)

一种方法是添加 uploadFileChunk (byte [] chunkData,int size,int offset,int totalSize)方法(或类似的东西),上传部分文件和服务器将其写入磁盘。

答案 7 :(得分:0)

请记住,Web服务请求基本上归结为单个HTTP POST。

如果您查看.NET中.ASMX文件的输出,它会准确显示POST请求和响应的内容。

正如@Guvante所提到的那样,Chunking将是最接近你想要的东西。

我认为您可以实现自己的Web客户端代码来处理TCP / IP并将内容流式传输到您的应用程序中,但至少可以说这很复杂。

答案 8 :(得分:0)

我认为使用简单的servlet进行此任务将是一种更简单的方法,或者有什么理由不能使用servlet?

例如,您可以使用Commons开源库。

答案 9 :(得分:0)

Java RMIIO库提供了跨RMI处理RemoteInputStream - 我们只需要RMI,但您应该能够调整代码以适应其他类型的RMI。这可能对您有所帮助 - 特别是如果您可以在用户端使用小型应用程序。该库的开发目的是能够限制推送到服务器的数据大小,以避免完全符合您描述的情况 - 通过填充RAM或磁盘实际上是DOS攻击。

使用RMIIO库,服务器端可以决定它愿意提取多少数据,使用HTTP PUT和POST,客户端可以做出决定,包括推送的速率。

答案 10 :(得分:0)

是的,网络服务可以进行流式传输。我使用Apache Axis2和MTOM创建了一个Web服务,以支持从XML呈现PDF文档。由于生成的文件可能非常大,因此流式传输非常重要,因为我们不希望将其全部保存在内存中。在streaming SOAP attachments.

上查看Oracle的文档

或者,您可以自己完成,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();

    }

答案 11 :(得分:0)

实际上并不难“处理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,因此您最终可能会在浏览器上出现错误,但实际上就是它的全部内容。

祝你好运!

罗德尼