为什么HttpURLConnection API中有流?

时间:2014-03-12 07:01:38

标签: java android http httpurlconnection

根据我对HTTP的理解,它的工作原理如下:客户端汇编一条消息,由一些头字段和(可能)一个主体组成,并将其发送到服务器。服务器处理它,组装自己的响应消息并将其发送回客户端。

所以我提出了这个问题:

为什么HttpURLConnection中有突然的流?

这对我没有意义。它使它看起来像一个连续的开放通道。消息实际上在什么时候发送到服务器?在connect?在getInputStream?当试图从流中读取?如果我有有效载荷,它会在不同的时间发送吗?我可以只用一个连接进行写 - 读 - 写 - 读吗?

我确定我还没有理解它,但是现在它对我来说似乎是一个糟糕的API。

我希望看到更多这样的东西:

HttpURLConnection http = url.openConnection();
HttpMessage req = new HttpMessage;
req.addHeader(...);
req.setBody(...);
http.post(req);

// Block until response is available (Future pattern)
HttpMessage res = http.getResponse();

6 个答案:

答案 0 :(得分:2)

虽然底层传输确实是使用单个数据包进行的,但并不能保证您认为单个http请求/响应的内容将适合"在一个http"数据包"。反过来,也不能保证单个http"数据包"将适合单个tcp数据包,依此类推。

想象一下使用http下载20MB的图像。它的单一http"响应"但我保证在浏览器和提供它的网站之间会有多个数据包来回传递。

每个块在每个级别都可能包含多个较小的块,并且因为您可能在它的所有不同位到达之前开始处理响应,并且您真的不想关注它们中有多少是,流是对此的共同抽象。

答案 1 :(得分:2)

恕我直言HttpURLConnection确实有一个糟糕的API。但是将输入和输出消息作为流处理是一种有效处理大量数据的方法。我认为所有其他答案(此刻5!)都是正确的。有一些问题是开放的:

  

邮件在什么时候实际发送到服务器?在连接?在getInputStream?当试图从流中读取?

当所有收集的数据(例如标题,超时选项......)实际传输到服务器时,会有一些触发器。在大多数情况下,您不必致电connect,这是隐含的,例如致电getResponseCode()getInputStream()时。 (顺便说一下,我建议在getResponseCode()之前调用getInputStream(),因为如果您收到错误代码(例如404),getInputStream将抛出异常,您最好调用getErrorStream()。)

  

如果我有有效载荷,它会在不同的时间发送吗?

您必须致电getOutputStream()然后发送有效负载。在添加标题后(显然)应该这样做。关闭流后,您可以期待服务器的响应。

  

我可以只用一个连接进行写 - 读 - 写 - 读吗?

没有。从技术上讲,这可以在使用keep-alive时实现。但是HttpURLConnection在封面下处理这个问题,你只能用这个类的实例进行一次请求 - 响应往返。

让生活更轻松

如果您不想与HttpURLConnection的可怕API进行斗争,您可以查看DavidWebb上列出的一些抽象API。使用DavidWebb时,典型请求如下所示:

Webb webb = Webb.create();
String result = webb.post("http://my-server/path/resource")
    .header("auth-token", myAuthToken)
    .body(myBody)
    .ensureSuccess()
    .asString()
    .getBody();

答案 2 :(得分:1)

这里Http协议适用于面向连接的TCP连接。所以在内部,它创建了一个TCP连接。然后发送http请求并接收回复。然后删除TCP连接。这就是为什么有两种不同的流。

答案 3 :(得分:1)

因为流是在Java中两个位置之间推送数据的通用方式,而这就是HTTP连接的作用。 HTTP通过TCP工作,这是一个流连接,所以这个API模仿它。

至于为什么它没有进一步抽象 - 考虑到HTTP请求中没有大小限制。例如,文件上传可以是许多MB甚至GB。

使用流式API,您可以从文件或其他来源读取数据,同时通过连接将其流式传输,而无需一次性将所有数据加载到内存中。

答案 4 :(得分:1)

流式响应可以动态消耗而不是分配本地内存中的所有数据,因此从内存的角度来看会更好,例如,如果你要解析一个巨大的json文件,从流和消耗后丢弃原始数据。从理论上讲,解析可以在第一个字节到达后立即开始。

发送/接收部分以及启动基础套接字的创建是getInputStream

答案 5 :(得分:1)

TCP 是一个字节流。 HTTP请求或响应的主体是任意字节流。不确定您期望的是哪种API,但是当您有字节流数据时,您将获得字节流API。