Java HTTP全双工

5
我有一个运行在Jersey (GlassFish 3.1.1)上的RESTful Web服务,它使用HTTP流传输方式,这是有点不寻常的。客户端和服务器通过长时间运行的对话来发送编码为XML标签的消息。这样做的主要原因是服务器可以向客户端推送数据。
我有一个测试客户端,它使用HttpURLConnection。问题在于,客户端的OutputStream或服务器的InputStream可能会过早关闭。当我尝试从客户端发送一些XML时,就会抛出ProtocolException(无法在读取输入后写入输出)。
当我使用WizTools RESTClient进行测试时,我可以发布XML请求,但该工具不允许保持连接处于活动状态。但至少我知道Web服务在这种情况下起作用。 (在流传输方案中,它可能完全正常;我猜测HttpURLConnection让我失望了。)
有没有办法使HttpURLConnection保持活动状态,并让我有机会实际向OutputStream发送内容?而且,在接收到InputStream数据后,有没有办法让它继续向OutputStream写入数据?
更新:
看起来HttpURLConnection正在执行HTTP的常规用法,即客户端必须在完全发送请求(并关闭输出流)之前无法处理响应。是否有另一种方法允许请求和响应在时间上重叠?我刚开始研究Apache HttpClient,但我还没有找到任何迹象表明这是可能的,因此我不确定是否在浪费时间。

你是想同时保持两个连接处于活动状态吗?我认为你只需要保持“服务器->客户端”连接处于开放状态以便将数据推送给客户端即可。当客户端需要向服务器发送数据时,你可以发送一个“常规”的HTTP请求,然后关闭连接。 - Michael
感谢 @Michael。只有一个连接。这不是严格的单向服务器推送。更像是服务器问客户端一个问题,客户端回答。虽然我可以为从客户端到服务器发送消息(持久或非持久)使用单独的连接,但如果可能的话,我宁愿避免这种复杂性。 - Steve
不,我认为这就是问题所在。你需要两个独立的连接。一个连接用于将问题推送给客户端,另一个连接用于将答案发送到服务器。 - Michael
@Steve 在服务器上使用普通的servlet(而不是Jersey),并在客户端使用HttpURLConnection可能会奏效。就像你在对@AlfredoO的评论中所说的那样,Jersey可能无法对打开/关闭/刷新连接进行细粒度控制(尽管可能有高级的配置方式来适应你的需求)。 - Michael
@SteveTaylor 是的,那很有道理。这就是HTTP的工作原理。客户端向服务器发送请求。一旦服务器接收到完整的请求,它就会将响应发送给客户端。你不能同时流传请求和响应,因为服务器在接收到整个请求之前无法开始发送响应。 - Michael
显示剩余7条评论
1个回答

3
您不应该在从InputStream读取数据之后写入更多数据,因为这不符合HTTP协议的性质,它是请求-响应的。关于此,请在此处了解更多信息。

感谢您的回答和链接。我已经阅读并理解了其中的要点。然而,我们已经有很多方法来扩展HTTP协议,其中之一就是服务器推送。那个链接中被接受的答案似乎特别提到了HttpURLConnection,而不是HTTP协议中可能存在或不存在的内容。也许,Jersey确实不会在收到整个请求之前调用资源方法,并传递包含主体的InputStream。如果是这种情况,那么我将不得不使用两个连接。在那之前,我有兴趣探索替代HttpURLConnection的方法。 - Steve
1
另一种选择是 Http Components Client http://hc.apache.org/httpcomponents-client-ga/。 - Alfredo Osorio
谢谢@Alfredo O. 正在阅读。 - Steve
我接受了这个答案,尽管它不是我想听到的。虽然我认为可能可以使用其他东西而不是HttpURLConnection来实现,但这可能会引发一系列问题。现在我正在使用两个连接(一个GET,一个POST),它运行良好。我想这就是将其强行塞入HTTP所要付出的代价。 - Steve
HTTP连接可以被重复使用,这并没有什么不可行之处。Http Keep-Alive就是一个例子。当然,这并不意味着Java支持它,但也不能归咎于协议。 - Basic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接