Ответ 1
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) {
// ...
}
Первые 3 ответа на ваши вопросы перечислены в виде встроенных комментариев, помимо каждого метода, в примере HTTP POST выше.
От getOutputStream:
Возвращает выходной поток, который записывается в это соединение.
В принципе, я думаю, вы хорошо понимаете, как это работает, поэтому позвольте мне просто повторить в непрофессиональных условиях. getOutputStream
в основном открывает поток , с целью записи данных на сервер. В приведенном выше примере кода "сообщение" может быть комментарием, который мы отправляем на сервер, который представляет комментарий, оставленный в сообщении. Когда вы видите getOutputStream
, вы открываете поток для записи, но вы фактически не записываете никаких данных, пока не назовете writer.write("message=" + message);
.
От getInputStream():
Возвращает поток ввода, который читается из этого открытого соединения. Исключение SocketTimeoutException может быть выбрано при чтении из возвращаемого потока ввода, если истечет время ожидания чтения до того, как данные доступны для чтения.
getInputStream
делает обратное. Как и getOutputStream
, он также открывает поток connection, но целью является считывание данных с сервера, а не запись на него. Если соединение или открытие потока не удастся, вы увидите SocketTimeoutException
.
Как получить getInputStream? Поскольку я могу получить ответ только в getInputStream, значит, я еще не отправил запрос в getOutputStream, но просто установил соединение?
Имейте в виду, что отправка запроса и отправка данных - это две разные операции. Когда вы вызываете getOutputStream или getInputStream url.openConnection()
, вы отправляете запрос на сервер для установления соединения. Существует рукопожатие, которое происходит там, где сервер отправляет вам подтверждение, что соединение установлено. Именно в этот момент вы готовы отправить или получить данные. Таким образом, вам не нужно вызывать getOutputStream для установить соединение, чтобы открыть поток, если только ваша цель для отправки запроса - отправить данные.
В условиях неспециалиста запрос getInputStream
является эквивалентом звонка в дом вашего друга, чтобы сказать: "Эй, хорошо, если я приеду и возьму эту пару тисков?" и ваш друг устанавливает рукопожатие, говоря: "Конечно, приходите и получите". Затем, в этот момент, соединение сделано, вы ходите в свой дом друзей, стучите в дверь, просите тиски и возвращаетесь в свой дом.
Использование аналогичного примера для getOutputStream
предполагает привлечение вашего друга и высказывание "Эй, у меня есть те деньги, которые я вам должен, могу ли я отправить вам"? Твой друг, нуждающийся в деньгах и больных, которые ты так долго хранил, говорит: "Конечно, перейди к тебе, дешевый ублюдок". Итак, вы ходите в дом своего друга и "ПОЧТАЙТЕ" деньги ему. Затем он вышвырнет вас, и вы вернетесь в свой дом.
Теперь, продолжая пример непрофессионала, давайте посмотрим на некоторые Исключения. Если вы позвонили своему другу и его не было дома, это может быть ошибка 500. Если вы позвонили и получили сообщение с отключенным номером, потому что ваш друг устал от того, что вы все время заимствуете деньги, что 404 страницы не найдены. Если ваш телефон мертв, потому что вы не оплатили счет, это может быть исключение IOException. (ПРИМЕЧАНИЕ. Этот раздел может быть не на 100% правильным. Он предназначен для того, чтобы дать вам общее представление о том, что происходит в условиях непрофессионала.)
Вопрос № 5:
Да, вы правы, что openConnection просто создает новый объект подключения, но не устанавливает его. Соединение устанавливается при вызове getInputStream или getOutputStream.
openConnection
создает новый объект подключения. Из URL.openConnection javadocs:
Новое соединение открывается каждый раз, вызывая метод openConnection обработчика протокола для этого URL.
Соединение устанавливается при вызове 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 закрывается?.