Web服务可以返回流吗?

时间:2020-03-06 14:42:52  来源:igfitidea点击:

我一直在写一个小应用程序,它可以使人们向我上传和下载文件。我已在此应用程序中添加了一个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),那肯定会尝试将所有这些信息放入内存中并导致我的服务崩溃。

所以我的问题是是否可以返回某种流?我想这不会是完全独立于OS的。尽管我了解Web服务背后的理论,但实际方面仍然是我需要了解的一些信息。

为任何投入而欢呼,
背风处

解决方案

Stephen Denne的Metro实施可以满足要求。在简短解释之后,下面提供了我的答案。

使用HTTP作为消息协议构建的大多数Web Service实现都是REST兼容的,因为它们仅允许简单的收发模式,仅此而已。由于所有各种平台都可以理解这种简单的体系结构(例如,与.NET Web服务对话的Java Web服务),因此,这极大地提高了互操作性。

如果要保持此状态,可以提供分块。

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

如果我们没有以正确的顺序获取块(或者我们可以只要求以正确的顺序来获取块),这将需要一些工作量,但是它可能很容易实现。

一种方法是添加一个uploadFileChunk(byte [] chunkData,int大小,int偏移量,int totalSize)方法(或者类似的方法)来上传文件的一部分,然后服务器将其写入磁盘。

是的,Metro可以实现。请参阅大型附件示例,它看起来像我们想要的那样。

JAX-WS RI provides support for sending and receiving large attachments in a streaming fashion.
  
  
  Use MTOM and DataHandler in the programming model.
  Cast the DataHandler to StreamingDataHandler and use its methods.
  Make sure you call StreamingDataHandler.close() and also close the StreamingDataHandler.readOnce() stream.
  Enable HTTP chunking on the client-side.

当我们使用标准化的Web服务时,发送者和接收者确实依赖从一个发送到另一个的XML数据的完整性。这意味着仅当发送最后一个标签时,Web服务请求和答案才完整。考虑到这一点,不能将Web服务视为流。

这是合乎逻辑的,因为标准化的Web服务确实依赖于http协议。那是"无状态的",会说它像"打开连接...发送请求...接收数据...关闭请求"一样工作。无论如何,连接将在最后关闭。因此,此处不打算使用流式传输。或者,他位于http之上(例如Web服务)。

非常抱歉,但据我所知,Web服务中没有流式传输的可能性。更糟糕的是:根据Web服务的实现/配置,byte []数据可能会转换为Base64,而不是CDATA标签,并且请求可能会变得更加肿。

附注:是的,正如其他人所写,"颠簸"是可能的。但这绝对不是流媒体;-),它可能会对我们有所帮助。

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

如果查看.NET中.ASMX文件的输出,它将确切显示POST请求和响应的外观。

@Guvante提到,分块将是我们想要的最接近的东西。

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

我认为为此任务使用简单的servlet会更容易,或者是否有任何原因不能使用servlet?

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

Java的RMIIO库提供了跨我们仅需要RMI的RMI处理RemoteInputStream的能力,尽管我们应该能够使代码适应于其他类型的RMI。这可能对我们有帮助,特别是如果我们可以在用户端拥有一个小型应用程序。开发该库的明确目的是能够限制推送到服务器的数据大小,从而避免完全填满ram或者磁盘来有效描述DOS攻击的情况。

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

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

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

我认为一个局限性是,如果我们要流式传输,则只能有一个邮件正文成员(这种方式有意义)。

Apache CXF支持发送和接收流。