安全使用 HttpURLConnection
使用 HttpURLConnection 时,如果我们不“获取”并使用它,是否需要关闭 InputStream?
即这安全吗?
HttpURLConnection conn = (HttpURLConnection) uri.getURI().toURL().openConnection();
conn.connect();
// check for content type I don't care about
if (conn.getContentType.equals("image/gif") return;
// get stream and read from it
InputStream is = conn.getInputStream();
try {
// read from is
} finally {
is.close();
}
其次,在所有内容被完全读取之前关闭输入流是否安全?
是否存在使底层套接字处于 ESTABLISHED 甚至 CLOSE_WAIT 状态的风险?
When using HttpURLConnection does the InputStream need to be closed if we do not 'get' and use it?
i.e. is this safe?
HttpURLConnection conn = (HttpURLConnection) uri.getURI().toURL().openConnection();
conn.connect();
// check for content type I don't care about
if (conn.getContentType.equals("image/gif") return;
// get stream and read from it
InputStream is = conn.getInputStream();
try {
// read from is
} finally {
is.close();
}
Secondly, is it safe to close an InputStream before all of it's content has been fully read?
Is there a risk of leaving the underlying socket in ESTABLISHED or even CLOSE_WAIT state?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
根据 http://docs.oracle.com /javase/6/docs/technotes/guides/net/http-keepalive.html
和 OpenJDK 源代码。
(当keepAlive == true时)
如果客户端调用
HttpURLConnection.getInputSteam().close()
,则稍后调用HttpURLConnection。 disconnect()
将不会关闭Socket
。即Socket
被重用(缓存)如果客户端不调用
close()
,调用disconnect()
将关闭InputStream< /code> 并关闭
Socket
。因此,为了重用
Socket
,只需调用InputStream.close()
即可。不要调用HttpURLConnection.disconnect()
。According to http://docs.oracle.com/javase/6/docs/technotes/guides/net/http-keepalive.html
and OpenJDK source code.
(When
keepAlive == true
)If client called
HttpURLConnection.getInputSteam().close()
, the later call toHttpURLConnection.disconnect()
will NOT close theSocket
. i.e. TheSocket
is reused (cached)If client does not call
close()
, calldisconnect()
will close theInputStream
and close theSocket
.So in order to reuse the
Socket
, just callInputStream.close()
. Do not callHttpURLConnection.disconnect()
.在关闭输入流之前,您需要读取输入流中的所有数据,以便缓存底层 TCP 连接。我读到,在最新的 Java 中不应该要求它,但总是强制要求读取整个响应以进行连接重用。
检查这篇文章:在java6中保持活动
You need to read all of the data in the input stream before you close it so that the underlying TCP connection gets cached. I have read that it should not be required in latest Java, but it was always mandated to read the whole response for connection re-use.
Check this post: keep-alive in java6
以下是有关保持活动缓存的一些信息。所有这些信息都与 Java 6 相关,但对于许多先前和更高版本也可能是准确的。
据我所知,代码归结为:
该逻辑分为两个地方: sun.net.www.http.HttpClient (在“parseHTTPHeader”方法中),以及大约第 120 行 sun.net.www.http.KeepAliveCache(在“put”方法中)。
因此,有两种方法可以控制超时时间:
人们可能会认为可以在不重新编译内部 JDK 类的情况下更改明显任意的 5 秒默认值,但事实并非如此。 2005 年提交了一个 bug 请求此功能,但 Sun 拒绝提供。
Here is some information regarding the keep-alive cache. All of this information pertains Java 6, but is probably also accurate for many prior and later versions.
From what I can tell, the code boils down to:
This logic is split between two places: around line 725 of sun.net.www.http.HttpClient (in the "parseHTTPHeader" method), and around line 120 of sun.net.www.http.KeepAliveCache (in the "put" method).
So, there are two ways to control the timeout period:
One would think that it would be possible to change the apparently arbitrary five-second default without recompiling internal JDK classes, but it isn't. A bug was filed in 2005 requesting this ability, but Sun refused to provide it.
如果您确实想确保连接已关闭,您应该调用conn.disconnect()。
您观察到的打开连接是由于 HTTP 1.1 连接保持活动功能(也称为 HTTP 持久连接)。
如果服务器支持 HTTP 1.1 并且不在响应标头中发送
Connection: close
,则当您关闭输入流时,Java 不会立即关闭底层 TCP 连接。相反,它保持其打开状态,并尝试将其重新用于对同一服务器的下一个 HTTP 请求。如果您根本不希望出现此行为,可以将系统属性
http.keepAlive
设置为 false:If you really want to make sure that the connection is close you should call
conn.disconnect()
.The open connections you observed are because of the HTTP 1.1 connection keep alive feature (also known as HTTP Persistent Connections).
If the server supports HTTP 1.1 and does not send a
Connection: close
in the response header Java does not immediately close the underlaying TCP connection when you close the input stream. Instead it keeps it open and tries to reuse it for the next HTTP request to the same server.If you don't want this behaviour at all you can set the system property
http.keepAlive
to false:是的,它总是需要关闭。
不是 100%,您就有获得 NPE 的风险。更安全的是:
Yes, it always needs to be closed.
Not 100%, you run the risk of getting a NPE. Safer is:
如果 HTTP 请求失败(除了 200),您还必须关闭错误流:
如果您不这样做,所有不返回 200(例如超时)的请求都将泄漏一个套接字。
You also have to close error stream if the HTTP request fails (anything but 200):
If you don't do it, all requests that don't return 200 (e.g. timeout) will leak one socket.
从 Java 7 开始,推荐的方法与
所有其他实现
Closable
的类一样。close()
在try {...}
块的末尾调用。关闭输入流也意味着您已完成阅读。否则,连接将挂起,直到终结器关闭流。
如果您要发送数据,同样适用于输出流。
无需关闭 ErrorStream。即使它实现了InputStream 接口:它也将InputStream 与缓冲区结合使用。关闭 InputStream 就足够了。
Since Java 7 the recommended way is
as for all other classes implementing
Closable
.close()
is called at the end of thetry {...}
block.Closing the input stream also means you are done with reading. Otherwise the connection hangs around until the finalizer closes the stream.
Same applies to the output stream, if you are sending data.
There is no need to get an close the ErrorStream. Even if it implements the InputStream interface: It's using the InputStream in combination with a buffer. Closing the InputStream is sufficient.