4

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

服务器基于com.sun.net.httpserver.HttpServer并允许使用 POST 和 PUT 操作通过基本 RESTful 接口上传文件。上传操作使用我们自己实现的Digest 身份验证进行限制,在浏览器、curl 和Apache HttpClient.

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

上传不同大小的文件时,可能会观察到奇怪的行为:

  • 大小小于或等于 1.076.006 字节的文件上传 成功
  • 大小大于或等于 1.122.158 字节的文件 失败并带有java.net.SocketException: Broken pipe.

确切的临界大小未知,因为我手动创建了不同大小的文件以接近最大工作大小

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

上传适用于各种大小的文件,所以没有问题。

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

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

4

1 回答 1

6

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

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

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

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

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

于 2012-02-07T12:40:32.337 回答