我正在使用java(和scala)开发和测试一个简单的直接客户端 - 服务器应用程序。
服务器基于com.sun.net.httpserver.HttpServer
,允许使用POST和PUT操作通过基本RESTful接口上传文件。使用我们自己实施的Digest authentication来限制上传操作,经过测试并在浏览器中使用,卷曲和Apache HttpClient
。
上传客户端包装Apache HttpClient 4.1.2
并通过http执行PUT操作以上传文件实体。文件的内容类型在标题中指定为application/xml
,一次只上传一个文件。
上传不同尺寸的文件时,可能会发现奇怪的行为:
java.net.SocketException: Broken pipe
。(确切的关键尺寸未知,因为我手动创建了不同尺寸的文件以接近最大工作尺寸)
管道损坏的原因是,客户端以某种方式忽略了www-authenticate
- 响应上传该大小的文件,如服务器日志所记录的那样。 “忽略”意味着它只发送多个(4)消息,根本不包含认证头。
但较小的文件运行良好,客户端会在www-authenticate
- 响应之后立即正确发送带有正确质询 - 响应的身份验证请求。
上传使用各种尺寸的文件卷曲,所以没问题。
所以在这一点上,人们可以说:“你的客户端有一些错误。”好吧,我有点希望如此,但是我也尝试过一个开源的java RESTclient (也包括apache httpclient),它的完全相同行为!
我们尝试通过互联网使用此客户端,它也与描述相同。所以现在,我只是希望我错过了在Apache HttpClient
设置一些重要的东西导致这种错误的行为,开源RESTclient的开发者也错过了它......任何想法可能会是什么意思太棒了!
答案 0 :(得分:6)
很可能是导致这种情况的几个因素的组合
(1)在发送包含不包含身份验证标头的请求的大型请求实体时,您的客户端很可能不会使用“expect-continue”握手。
(2)服务器很早就检测到请求未达到预期,而不是读取和丢弃完整的请求主体,它以401状态提前响应并在其结束时关闭连接。在我看来,这是服务器方面的HTTP协议违规。
(3)虽然一些HTTP代理可以处理早期响应,但是Apache HttpClient不能由于Java阻塞I / O的限制(执行线程可以从阻塞套接字读取或写入,但不能同时读取或写入)。
有多种方法可以解决这个问题,'期望 - 继续'握手是最简单,最自然的握手。或者,可以执行简单的HEAD或GET请求以在执行大的POST或PUT请求之前强制进行HTTP身份验证。 HttpClient能够在同一逻辑HTTP会话中为后续请求重用身份验证数据。