String message = URLEncoder.encode("my message", "UTF-8");
try {
// instantiate the URL object with the target URL of the resource to
// request
URL url = new URL("http://www.example.com/comment");
// instantiate the HttpURLConnection with the URL object - A new
// connection is opened every time by calling the openConnection
// method of the protocol handler for this URL.
// 1. This is the point where the connection is opened.
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
// set connection output to true
connection.setDoOutput(true);
// instead of a GET, we're going to send using method="POST"
connection.setRequestMethod("POST");
// instantiate OutputStreamWriter using the output stream, returned
// from getOutputStream, that writes to this connection.
// 2. This is the point where you'll know if the connection was
// successfully established. If an I/O error occurs while creating
// the output stream, you'll see an IOException.
OutputStreamWriter writer = new OutputStreamWriter(
connection.getOutputStream());
// write data to the connection. This is data that you are sending
// to the server
// 3. No. Sending the data is conducted here. We established the
// connection with getOutputStream
writer.write("message=" + message);
// Closes this output stream and releases any system resources
// associated with this stream. At this point, we've sent all the
// data. Only the outputStream is closed at this point, not the
// actual connection
writer.close();
// if there is a response code AND that response code is 200 OK, do
// stuff in the first if block
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
// OK
// otherwise, if any other status code is returned, or no status
// code is returned, do stuff in the else block
} else {
// Server returned HTTP error code.
}
} catch (MalformedURLException e) {
// ...
} catch (IOException e) {
// ...
}
在上面的 HTTP POST 示例中,您的问题的前 3 个答案被列为每个方法旁边的内联注释。
从getOutputStream:
返回写入此连接的输出流。
基本上,我认为你已经很好地理解了它是如何工作的,所以让我用外行的话重申一下。getOutputStream
基本上打开一个连接流,目的是向服务器写入数据。在上面的代码示例中,“消息”可以是我们发送到服务器的评论,代表在帖子上留下的评论。当您看到 时getOutputStream
,您正在打开连接流以进行写入,但在您调用 之前您实际上并没有写入任何数据writer.write("message=" + message);
。
从getInputStream():
返回从此打开的连接读取的输入流。如果读取超时在数据可供读取之前到期,则从返回的输入流读取时可能会引发 SocketTimeoutException。
getInputStream
相反。像getOutputStream
,它也打开了一个连接流,但目的是从服务器读取数据,而不是写入数据。如果连接或流打开失败,您将看到一个SocketTimeoutException
.
getInputStream 怎么样?既然我只能在 getInputStream 获得响应,那么这是否意味着我还没有在 getOutputStream 发送任何请求而只是建立了连接?
请记住,发送请求和发送数据是两个不同的操作。当您调用getOutputStream 或 getInputStream url.openConnection()
时,您向服务器发送请求以建立连接。在服务器向您发回连接已建立的确认时会发生握手。然后在那个时间点,您准备发送或接收数据。因此,您不需要调用 getOutputStream 来建立连接打开流,除非您发出请求的目的是发送数据。
通俗地说,提出一个getInputStream
请求就相当于给你朋友家打电话说“嘿,我过来借那副副把手可以吗?” 你的朋友通过说“当然!过来拿”来建立握手。然后,在那一点上,建立连接,你走到你朋友的房子,敲门,请求副把手,然后走回你的房子。
使用类似的例子getOutputStream
会涉及打电话给你的朋友并说“嘿,我有欠你的钱,我可以把它寄给你吗”?你的朋友需要钱,而且里面生病了,所以你把它藏了这么久,他说:“当然,来吧,你这个贱货”。所以你走到你朋友家,把钱“邮寄”给他。然后他把你踢出去,你走回你家。
现在,继续外行的例子,让我们看一些异常。如果你打电话给你的朋友而他不在家,那可能是一个 500 错误。如果您因为您的朋友厌倦了您一直在借钱而打电话并收到一条断开的号码消息,那就是找不到 404 页面。如果你的手机因为你没有支付账单而死机,那可能是一个 IOException。(注意:本节可能不是 100% 正确。它旨在让您以通俗的方式大致了解正在发生的事情。)
问题 #5:
是的,您是正确的,openConnection 只是创建了一个新的连接对象但没有建立它。当您调用 getInputStream 或 getOutputStream 时建立连接。
openConnection
创建一个新的连接对象。从URL.openConnection javadocs:
每次调用此 URL 的协议处理程序的 openConnection 方法都会打开一个新连接。
调用 openConnection 时建立连接,实例化时调用 InputStream、OutputStream 或两者。
问题 #6:
为了测量开销,我通常在整个连接块周围包装一些非常简单的计时代码,如下所示:
long start = System.currentTimeMillis();
log.info("Time so far = " + new Long(System.currentTimeMillis() - start) );
// run the above example code here
log.info("Total time to send/receive data = " + new Long(System.currentTimeMillis() - start) );
我确信有更高级的方法来测量请求时间和开销,但这通常足以满足我的需求。
有关关闭连接的信息(您没有询问),请参阅在 Java 中 URL 连接何时关闭?.