Как отправлять HTTP-запросы на Java

Введение Протокол передачи гипертекста (HTTP) - это протокол прикладного уровня, который, без преувеличения, в значительной степени является основой работы в Интернете в том виде, в каком мы его знаем. Он используется для передачи гипермедийных документов между клиентом и сервером и является неотъемлемой частью каждого веб-приложения, включая любые API-интерфейсы, использующие архитектуру REST. Он позволяет браузеру связываться с сервером, отправляя запросы на определенные документы, будь то документы HTML (возвращаемые как

Вступление

Протокол передачи гипертекста (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 --> 

Затем тело ответа будет отображено в нашем браузере, и нас встретит страница!

stackabuse_java{.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

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.

comments powered by Disqus

Содержание