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
в основном открывает поток соединения с целью записи данных на сервер. В приведенном выше примере кода «message» может быть комментарием, который мы отправляем на сервер, который представляет комментарий, оставленный в сообщении. Когда вы видите getOutputStream
, вы открываете поток соединения для записи, но вы фактически не пишете никаких данных, пока не позвоните writer.write("message=" + message);
.
Из getInputStream () :
Возвращает входной поток, который читает из этого открытого соединения. Исключение SocketTimeoutException может генерироваться при чтении из возвращенного входного потока, если истекает время ожидания до того, как данные станут доступны для чтения.
getInputStream
делает обратное. Мол getOutputStream
, он также открывает поток соединения , но цель состоит в том, чтобы читать данные с сервера, а не записывать на него. Если соединение или открытие потока не удалось, вы увидите a SocketTimeoutException
.
Как насчет getInputStream? Поскольку я могу получить ответ только на getInputStream, значит ли это, что я еще не отправлял запрос на getOutputStream, а просто установил соединение?
Помните, что отправка запроса и отправка данных - это две разные операции. Когда вы вызываете getOutputStream или getInputStream url.openConnection()
, вы отправляете запрос на сервер для установления соединения. Происходит рукопожатие, когда сервер отправляет вам подтверждение того, что соединение установлено. В этот момент вы готовы отправлять или получать данные. Таким образом, вам не нужно вызывать getOutputStream, чтобы установить соединение, открывающее поток, если только ваша цель не состоит в том, чтобы отправить данные.
С точки зрения непрофессионала, сделать getInputStream
запрос равносильно тому, чтобы позвонить в дом вашего друга и сказать: «Эй, все в порядке, если я приду и одолжу эту пару тисков?» и твой друг устанавливает рукопожатие, говоря: «Конечно! Приди и возьми его». Затем, в этот момент, соединение установлено, вы идете к дому вашего друга, стучите в дверь, запрашиваете тиски и возвращаетесь в свой дом.
Используя аналогичный пример, getOutputStream
вы можете позвонить своему другу и сказать: «Эй, у меня есть те деньги, которые я вам должен, могу ли я отправить их вам»? Твой друг, которому нужны деньги и больной, чтобы ты так долго хранил его, говорит: «Конечно, давай, дешевый ублюдок». Таким образом, вы идете к дому своего друга и "ПОСТ" деньги ему. Затем он выгоняет тебя, и ты возвращаешься к себе домой.
Теперь, продолжая пример с неспециалистом, давайте рассмотрим некоторые исключения. Если вы позвонили своему другу, а его нет дома, это может быть ошибкой 500. Если вы позвонили и получили сообщение об отключении номера, потому что ваш друг устал от того, что вы постоянно занимаете деньги, эта страница 404 не найдена. Если ваш телефон мертв, потому что вы не оплатили счет, это может быть IOException. (ПРИМЕЧАНИЕ. Этот раздел может быть не на 100% правильным. Он предназначен для того, чтобы дать вам общее представление о том, что происходит с точки зрения непрофессионала.)
Вопрос № 5:
Да, вы правы, что openConnection просто создает новый объект подключения, но не устанавливает его. Соединение устанавливается, когда вы вызываете getInputStream или getOutputStream.
openConnection
создает новый объект подключения. От javadocs URL.openConnection :
Новое соединение открывается каждый раз, вызывая метод 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-соединение закрывается? ,
Returns an output stream that writes to this connection.
иReturns an input stream that reads from this open connection.
. Выходной поток и входной поток отделены от соединения.Тим Брей представил краткий пошаговый отчет, заявив, что openConnection () не устанавливает фактическое соединение. Скорее, фактическое HTTP-соединение не устанавливается, пока вы не вызовете такие методы, как getInputStream () или getOutputStream ().
http://www.tbray.org/ongoing/When/201x/2012/01/17/HttpURLConnection
источник
На порту, указанном в URL, если есть, в противном случае 80 для HTTP и 443 для HTTPS. Я считаю, что это задокументировано.
При вызове getInputStream () или getOutputStream () или getResponseCode () без получения исключения.
Нет и нет.
Любой из них сначала подключается при необходимости, затем возвращает требуемый поток.
Смотри выше.
Да.
Соединение: требуется время, чтобы getInoutStream () или getOutputStream () потребовалось для возврата, в зависимости от того, что вы вызываете первым. Читайте: время от начала первого чтения до получения EOS.
источник
В какой момент HTTPURLConnection пытается установить соединение с данным URL?
Стоит уточнить, есть экземпляр UrlConnection, а также базовое соединение через сокет Tcp / Ip / SSL , 2 разные концепции. Экземпляр 'UrlConnection' или 'HttpUrlConnection' является синонимом одного запроса страницы HTTP и создается при вызове url.openConnection (). Но если вы делаете несколько url.openConnection () из одного экземпляра 'url', то, если вам повезет, они будут повторно использовать один и тот же сокет Tcp / Ip и SSL-рукопожатие ... что хорошо, если вы делать много запросов страниц на один и тот же сервер, особенно хорошо, если вы используете SSL, где накладные расходы на установку сокета очень высоки.
Смотрите: HttpURLConnection реализация
источник
Я прошел через упражнение для захвата низкоуровневого обмена пакетами и обнаружил, что сетевое соединение запускается только такими операциями, как getInputStream, getOutputStream, getResponseCode, getResponseMessage и т. Д.
Здесь происходит обмен пакетами, когда я пытаюсь написать небольшую программу для загрузки файла в Dropbox.
Ниже моя игрушка программа и аннотация
источник