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
, він також відкриває потік з'єднання , але намір полягає в тому, щоб читати дані з сервера, а не писати на нього. Якщо з'єднання або відкриття потоку не вдається, ви побачите 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-з'єднання? .