Apache HttpClient 4.x在上传较大文件时表现得很奇怪?

时间:2012-02-06 14:25:13

标签: java apache file-upload httpclient digest-authentication

我正在使用java(和scala)开发和测试一个简单的直接客户端 - 服务器应用程序。

服务器基于com.sun.net.httpserver.HttpServer,允许使用POST和PUT操作通过基本RESTful接口上传文件。使用我们自己实施的Digest authentication来限制上传操作,经过测试并在浏览器中使用,卷曲和Apache HttpClient

上传客户端包装Apache HttpClient 4.1.2并通过http执行PUT操作以上传文件实体。文件的内容类型在标题中指定为application/xml,一次只上传一个文件。

上传不同尺寸的文件时,可能会发现奇怪的行为:

  • 上传大小小于或等于1.076.006字节的文件 的成功即可。
  • 大小更大或等于1.122.158字节的文件 失败java.net.SocketException: Broken pipe

确切的关键尺寸未知,因为我手动创建了不同尺寸的文件以接近最大工作尺寸

管道损坏的原因是,客户端以某种方式忽略了www-authenticate - 响应上传该大小的文件,如服务器日志所记录的那样。 “忽略”意味着它只发送多个(4)消息,根本不包含认证头。 但较小的文件运行良好,客户端会在www-authenticate - 响应之后立即正确发送带有正确质询 - 响应的身份验证请求。

上传使用各种尺寸的文件卷曲,所以没问题。

所以在这一点上,人们可以说:“你的客户端有一些错误。”好吧,我有点希望如此,但是我也尝试过一个开源的java RESTclient (也包括apache httpclient),它的完全相同行为!

我们尝试通过互联网使用此客户端,它也与描述相同。所以现在,我只是希望我错过了在Apache HttpClient设置一些重要的东西导致这种错误的行为,开源RESTclient的开发者也错过了它......任何想法可能会是什么意思太棒了!

1 个答案:

答案 0 :(得分:6)

很可能是导致这种情况的几个因素的组合

(1)在发送包含不包含身份验证标头的请求的大型请求实体时,您的客户端很可能不会使用“expect-continue”握手。

(2)服务器很早就检测到请求未达到预期,而不是读取和丢弃完整的请求主体,它以401状态提前响应并在其结束时关闭连接。在我看来,这是服务器方面的HTTP协议违规。

(3)虽然一些HTTP代理可以处理早期响应,但是Apache HttpClient不能由于Java阻塞I / O的限制(执行线程可以从阻塞套接字读取或写入,但不能同时读取或写入)。

有多种方法可以解决这个问题,'期望 - 继续'握手是最简单,最自然的握手。或者,可以执行简单的HEAD或GET请求以在执行大的POST或PUT请求之前强制进行HTTP身份验证。 HttpClient能够在同一逻辑HTTP会话中为后续请求重用身份验证数据。