安全使用 HttpURLConnection

发布于 2024-10-14 04:06:14 字数 517 浏览 3 评论 0原文

使用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

安人多梦 2024-10-21 04:06:14

根据 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 to HttpURLConnection.disconnect() will NOT close the Socket. i.e. The Socket is reused (cached)

If client does not call close(), call disconnect() will close the InputStream and close the Socket.

So in order to reuse the Socket, just call InputStream.close(). Do not call HttpURLConnection.disconnect().

百善笑为先 2024-10-21 04:06:14

关闭输入流是否安全
在所有内容都被删除之前
阅读

在关闭输入流之前,您需要读取输入流中的所有数据,以便缓存底层 TCP 连接。我读到,在最新的 Java 中不应该要求它,但总是强制要求读取整个响应以进行连接重用。

检查这篇文章:在java6中保持活动

is it safe to close an InputStream
before all of it's content has been
read

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

日裸衫吸 2024-10-21 04:06:14

以下是有关保持活动缓存的一些信息。所有这些信息都与 Java 6 相关,但对于许多先前和更高版本也可能是准确的。

据我所知,代码归结为:

  1. 如果远程服务器发送带有可解析为正整数的“超时”值的“Keep-Alive”标头,则该秒数将用于超时。
  2. 如果远程服务器发送“Keep-Alive”标头,但没有可解析为正整数的“超时”值“usingProxy”为 true,则超时为 60秒。
  3. 在所有其他情况下,超时时间为 5 秒。

该逻辑分为两个地方: sun.net.www.http.HttpClient (在“parseHTTPHeader”方法中),以及大约第 120 行 sun.net.www.http.KeepAliveCache(在“put”方法中)。


因此,有两种方法可以控制超时时间:

  1. 控制远程服务器并将其配置为发送带有适当超时字段的 Keep-Alive 标头
  2. 修改 JDK 源代码并构建您自己的。

人们可能会认为可以在不重新编译内部 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:

  1. If the remote server sends a "Keep-Alive" header with a "timeout" value that can be parsed as a positive integer, that number of seconds is used for the timeout.
  2. If the remote server sends a "Keep-Alive" header but it doesn't have a "timeout" value that can be parsed as a positive integer and "usingProxy" is true, then the timeout is 60 seconds.
  3. In all other cases, the timeout is 5 seconds.

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:

  1. Control the remote server and configure it to send a Keep-Alive header with the proper timeout field
  2. Modify the JDK source code and build your own.

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.

痴情 2024-10-21 04:06:14

如果您确实想确保连接已关闭,您应该调用conn.disconnect()。

您观察到的打开连接是由于 HTTP 1.1 连接保持活动功能(也称为 HTTP 持久连接)。
如果服务器支持 HTTP 1.1 并且不在响应标头中发送 Connection: close,则当您关闭输入流时,Java 不会立即关闭底层 TCP 连接。相反,它保持其打开状态,并尝试将其重新用于对同一服务器的下一个 HTTP 请求。

如果您根本不希望出现此行为,可以将系统属性 http.keepAlive 设置为 false:

System.setProperty("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:

System.setProperty("http.keepAlive","false");
归途 2024-10-21 04:06:14

使用HttpURLConnection时,如果我们没有“获取”并使用它,是否需要关闭InputStream?

是的,它总是需要关闭。

这安全吗?

不是 100%,您就有获得 NPE 的风险。更安全的是:

InputStream is = null;
try {
    is = conn.getInputStream()
    // read from is
} finally {
    if (is != null) {
        is.close();
    }
}

When using HttpURLConnection does the InputStream need to be closed if we do not 'get' and use it?

Yes, it always needs to be closed.

i.e. is this safe?

Not 100%, you run the risk of getting a NPE. Safer is:

InputStream is = null;
try {
    is = conn.getInputStream()
    // read from is
} finally {
    if (is != null) {
        is.close();
    }
}
不喜欢何必死缠烂打 2024-10-21 04:06:14

如果 HTTP 请求失败(除了 200),您还必须关闭错误流:

try {
  ...
}
catch (IOException e) {
  connection.getErrorStream().close();
}

如果您不这样做,所有不返回 200(例如超时)的请求都将泄漏一个套接字。

You also have to close error stream if the HTTP request fails (anything but 200):

try {
  ...
}
catch (IOException e) {
  connection.getErrorStream().close();
}

If you don't do it, all requests that don't return 200 (e.g. timeout) will leak one socket.

鹤舞 2024-10-21 04:06:14

从 Java 7 开始,推荐的方法与

try (InputStream is = conn.getInputStream()) {
    // read from is
    // ...
}

所有其他实现 Closable 的类一样。 close()try {...} 块的末尾调用。

关闭输入流也意味着您已完成阅读。否则,连接将挂起,直到终结器关闭流。

如果您要发送数据,同样适用于输出流。

无需关闭 ErrorStream。即使它实现了InputStream 接口:它也将InputStream 与缓冲区结合使用。关闭 InputStream 就足够了。

Since Java 7 the recommended way is

try (InputStream is = conn.getInputStream()) {
    // read from is
    // ...
}

as for all other classes implementing Closable. close() is called at the end of the try {...} 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文