2012-02-06 92 views
4

我正在开发和测试一个使用java(和scala)的简单直观的客户端 - 服务器应用程序。Apache HttpClient 4.x在上传较大的文件时表现奇怪?

服务器基于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 -response上传该大小的文件,这是由服务器日志记录的。 “忽略”意味着它只发送多个(4)消息,其中不包含任何验证头。 但是较小的文件工作良好,客户端在www-authenticate响应之后立即正确发送具有正确质询 - 响应的认证请求,因为它应该是。

上传工作卷曲与所有大小的文件,所以没有问题。

因此,在这一点上,可以说:“您的客户端存在一些错误。”好吧,我有点希望,但我也试过一个开源的java RESTclient(也包装apache httpclient),它有正好相同的行为!

我们在互联网上使用此客户端进行了试用,其描述与上述相同。所以现在,我只希望我错过了在Apache HttpClient中设置一些重要的东西,这会导致这种错误的行为,而开源RESTclient的开发人员也错过了它......任何想法都可能会很棒!

回答

6

它最有可能是几个因素的结合,导致这种情况

(1)最有可能你的客户不使用“期望继续”用未请求发送大量请求的实体时握手包含一个验证标题。(2)服务器尽早检测到请求不符合期望,而不是读取并丢弃完整的请求体,它以401状态提前响应,并在其结束时关闭连接。在我看来,这是服务器部分违反HTTP协议的原因。 (3)尽管一些HTTP代理可以处理早期响应,但由于Java阻塞I/O的限制,Apache HttpClient不能实现(一个执行线程可以从阻塞套接字读取或写入数据,但不能同时使用两者) 。

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

+0

感谢您的解释,它非常有意义!现在我去寻求'继续'的解决方案。在客户端它只是翻转一个布尔值。现在服务器握手正在进行中,我相信这应该可以解决问题。 – mtsz 2012-02-07 17:09:07

+0

奇怪的是,底层的sun httpserver *始终*以100次继续响应,而不涉及应用程序!在我看来,它违反了协议(请参阅RFC 2616“使用100(继续)状态”,httpserver-source:http://www.docjar.com/html/api/sun/net/httpserver/ServerImpl。 java.html)。但是在发送大量数据之前,我已经使用第二个请求实现了第二个解决方案触发身份验证。这工作,所以非常感谢! – mtsz 2012-02-08 15:12:16

+0

@mtsz这不关我的事,但为什么现在有这么多像样的嵌入式HTTP服务器时,你一直在使用Sun的ServerImpl? – oleg 2012-02-08 15:46:14

相关问题