Вступление
Протокол передачи гипертекста (HTTP) - это протокол прикладного уровня, который, без преувеличения, в значительной степени является основой работы в Интернете в том виде, в каком мы его знаем.
Он используется для передачи гипермедийных документов между клиентом и сервером и является неотъемлемой частью каждого веб-приложения, включая любые API-интерфейсы, использующие архитектуру REST.
Он позволяет браузеру связываться с сервером, отправляя запросы на определенные документы, будь то документы HTML (возвращаемые в виде страниц, которые мы видим) или гипермедиа (изображения, видео и т. Д.), Которые обслуживаются на страницах.
Как работает HTTP?
Когда мы решаем посетить веб-сайт, за кулисами происходит то, что наш компьютер генерирует и отправляет запрос на сервер, на котором размещен веб-сайт.
HTTP-запрос может выглядеть примерно так:
GET /tag/java/ HTTP/1.1
Host: stackabuse.com
Accept: */*
User-Agent: Mozilla/5.0 (platform; rv:geckoversion) Gecko/geckotrail Firefox/firefoxversion
Здесь мы просим сервер отправить обратно страницу по URL-адресу
stackabuse.com/tag/java/
используя HTTP версии 1.1.
Сервер должен ответить примерно так:
HTTP/1.1 200 OK
Date: Fri, 01 Feb 2019 22:07:06 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=dd40ff971a6cefddc4855e028541f79581549051234; expires=Sat, 01-Feb-20 22:07:06 GMT; path=/; domain=.stackabuse.com; HttpOnly; Secure
...
Далее следует тело ответа :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>java - Page 1 - Stack Abuse</title>
<meta name="description" content="" />
<meta name="keywords" content="">
<!-- rest of the page -->
Затем тело ответа будет отображено в нашем браузере, и нас встретит страница!
{.ezlazyload}
Помимо HTTP/1.1 200 OK
который мы получили в ответ, есть еще несколько
других, с которыми вы, вероятно, сталкивались в своей повседневной
жизни:
- 1xx : Любой статус, начинающийся с «1», является информационным статусом. Запрос получен и обрабатывается.
- 2xx : любой статус, начинающийся с «2», означает, что запрос был
успешным . В большинстве случаев это
200 OK
что просто означает, что все прошло гладко. - 3xx : любой статус, начинающийся с «3», означает, что пользователя нужно перенаправить, чтобы завершить действие.
- 4xx : любой статус, начинающийся с «4», указывает на ошибку
клиента . Самый известный -
404 Not Found
, обычно из-за неправильного запроса или синтаксиса. Наряду с этим есть400 Bad Request
,401 Unauthorized
и403 Forbidden
. Эти коды состояния являются наиболее распространенными, и их очень много. - 5xx : любой статус, начинающийся с «5», указывает на ошибку сервера .
Полный список кодов состояния HTTP довольно длинный, хотя неплохо было бы его просмотреть.
Отправка запросов с HttpURLConnection
- это базовый класс Java для обработки HTTP-запросов и ответов.
Использование HttpURLConnection
идеально подходит для простых
HTTP-запросов, хотя, если вы хотите более легко добавлять такие вещи,
как заголовки или аутентификация, вам будет легче полагаться на другие
библиотеки, такие как Apache Commons.
Самый простой способ создать экземпляр HttpURLConnection
-
использовать объект URL
URL url = new URL("https://www.stackabuse.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
Типы запросов
Теперь, HttpURLConnection
существует наш экземпляр HttpURLConnection,
мы можем определить для него тип HTTP-запроса:
// For a GET request
connection.setRequestMethod("GET");
// For a POST request
connection.setRequestMethod("POST");
// For a HEAD request
connection.setRequestMethod("HEAD");
// For a OPTIONS request
connection.setRequestMethod("OPTIONS");
// For a PUT request
connection.setRequestMethod("PUT");
// For a DELETE request
connection.setRequestMethod("DELETE");
// For a TRACE request
connection.setRequestMethod("TRACE");
Хотя в большинстве случаев вы будете использовать только GET , POST и DELETE .
Параметры запроса
В некоторых случаях нам нужно отправить HTTP-запрос с определенными
параметрами запроса, например www.youtube.com/watch?v=dQw4w9WgXcQ
.
Для этого мы обычно придумывали способ объединить эти значения в пары.
Иногда люди определяют свои собственные классы для хранения этих
значений, хотя простой HashMap
подойдет:
Map<String, String> params = new HashMap<>();
params.put("v", "dQw4w9WgXcQ");
Теперь, когда у нас есть сопоставленные параметры, нам нужно сделать несколько вещей, чтобы подготовить их к нашему запросу:
- Сгенерируйте параметр в строковом формате. Мы будем использовать
StringBuilder
поскольку он идеально подходит для конкатенации, которую мы будем выполнять - Используйте класс URLEncoder для кодирования наших параметров
- Преобразуйте данные в байты, поскольку наш
DataOutputStream
который запускает запрос, ожидает массив типаbyte
Примечание . Если вы не уверены, почему нам нужно кодировать наш URL-адрес - это потому, что некоторые символы могут иметь особое значение в URL-адресах. Такие символы, как «/», «.», «#» И «?» может изменить запрос, поэтому, если они присутствуют, нам нужно закодировать их таким образом, чтобы это не повлияло на интерпретацию URL-адреса.
Реализуем пункты из списка:
// Instantiate a requestData object to store our data
StringBuilder requestData = new StringBuilder();
for (Map.Entry<String, String> param : params.entrySet()) {
if (requestData.length() != 0) {
requestData.append('&');
}
// Encode the parameter based on the parameter map we've defined
// and append the values from the map to form a single parameter
requestData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
requestData.append('=');
requestData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
// Convert the requestData into bytes
byte[] requestDataByes = requestData.toString().getBytes("UTF-8");
Итак, наш параметр готов к использованию в запросе.
Заголовки запроса
Если вы хотите добавить заголовок к запросу, это очень просто:
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Content-Length", String.valueOf(requestDataBytes.length));
И если вы хотите прочитать заголовок из запроса:
String contentType = connection.getHeaderField("Content-Type");
Таймауты
Еще одна функция, HttpURLConnection
- это установка тайм-аутов .
Мы можем определить интервалы тайм-аута для чтения или подключения:
connection.setConnectTimeout(10000);
connection.setReadTimeout(10000);
Интервалы, как обычно, определяются в миллисекундах.
Так, например, соединение будет отключено по таймауту, если оно не может быть установлено в течение 10 секунд. Точно так же он также истечет, если данные не могут быть прочитаны из соединения в течение 10 секунд.
POST запрос
Когда наш запрос настроен, мы можем продолжить и запустить запрос POST:
// Set the doOutput flag to true
connection.setDoOutput(true);
// Get the output stream of the connection instance
// and add the parameter to the request
try (DataOutputStream writer = new DataOutputStream(connection.getOutputStream())) {
writer.write(postDataBytes);
// Always flush and close
writer.flush();
writer.close();
}
Здесь мы отправляем postDataBytes
в нашем запросе POST , который
представляет собой массив байтов. Ознакомьтесь с демонстрацией ниже,
чтобы узнать больше о том, как это сгенерировать.
GET запрос
Как только мы отправляем запрос POST , мы обычно хотим что-то сделать (или хотя бы просмотреть) ответ.
Запросы GET предназначены только для получения данных, поэтому давайте продолжим и получим ответ:
// To store our response
StringBuilder content;
// Get the input stream of the connection
try (BufferedReader input = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line;
content = new StringBuilder();
while ((line = input.readLine()) != null) {
// Append each line of the response and separate them
content.append(line);
content.append(System.lineSeparator());
}
} finally {
connection.disconnect();
}
// Output the content to the console
System.out.println(content.toString());
Мы можем извлечь много различных видов информации от connection
на
данный момент:
// Returns the value of the content-type header field
connection.getContentType();
// Returns an unmodifiable Map of the header fields
connection.getHeaderFields();
// Gets the status code from an HTTP response message
connection.getResponseCode();
// Gets the HTTP response message returned along with the response code from a server
connection.getResponseMessage();
// Returns the error stream if the connection failed but the server sent useful data nonetheless
connection.getErrorStream();
// ...etc
Демо
Вот как очень простое приложение сгенерирует запрос POST , отправит его, а затем прочитает ответ:
public static void main(String[] args) throws MalformedURLException, ProtocolException, IOException {
URL url = new URL("https://www.youtube.com");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
Map<String, String> params = new HashMap<>();
params.put("v", "dQw4w9WgXcQ");
StringBuilder postData = new StringBuilder();
for (Map.Entry<String, String> param : params.entrySet()) {
if (postData.length() != 0) {
postData.append('&');
}
postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
postData.append('=');
postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
}
byte[] postDataBytes = postData.toString().getBytes("UTF-8");
connection.setDoOutput(true);
try (DataOutputStream writer = new DataOutputStream(connection.getOutputStream())) {
writer.write(postDataBytes);
writer.flush();
writer.close();
StringBuilder content;
try (BufferedReader in = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String line;
content = new StringBuilder();
while ((line = in.readLine()) != null) {
content.append(line);
content.append(System.lineSeparator());
}
}
System.out.println(content.toString());
} finally {
connection.disconnect();
}
}
Выполнение этого фрагмента кода, безусловно, дает исходный код страницы, которую мы указали для получения:
<!DOCTYPE html>
<html lang="sr" data-cast-api-enabled="true">
<head>
<!-- rest of the page -->
Заключение
Протокол передачи гипертекста (HTTP) - это протокол прикладного уровня, который, без преувеличения, является очень большим и важным компонентом Интернет-приложений.
HttpURLConnection
- это базовый класс Java для обработки HTTP-запросов
и ответов.
Использование HttpURLConnection
идеально подходит для простых
HTTP-запросов, хотя, если вы хотите создать более сложные HTTP-запросы с
заголовками или аутентификацией, у вас будет гораздо более простой опыт
работы с такими библиотеками, как Apache Commons.