JavaRush/Курсы/Java Syntax Pro/Работа с сетью

Работа с сетью

Открыта

1. Класс URL

Работу с потоками ввода-вывода мы уже изучили, работу с файлами изучили, что же изучить дальше? А как насчет работы с сетью и интернетом? Звучит многообещающе, не так ли?

В Java работать с интернетом не сложнее, чем работать с файлами. Ну разве что совсем чуть-чуть.

Для работы с ресурсами в интернете в Java есть специальный класс — URL. Он простой, как табуретка, в чем вы сейчас и убедитесь.

Получение странички из интернета

Как вы думаете, сколько строк кода нужно написать, чтобы скачать какой-нибудь текстовый файл из интернета и отобразить его содержимое на экране? 10? 100? 1000? А может быть, 5?

Код Примечание
URL url = new URL("https://javarush.com");
InputStream input = url.openStream();
byte[] buffer = input.readAllBytes();
String str = new String(buffer);
System.out.println(str);
Создает объект URL с путем к странице
Получает InputStream у интернет-объекта
Читает все байты и возвращает массив байт
Преобразуем массив в строку
Выводим строку на экран

На экране отобразится содержимое HTML-файла:

Вывод на экран
<!DOCTYPE html><html lang="ru" class="light"><head>
    <meta charset="utf-8″>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1″>
    ...

Сравнение работы File и URL

URL — это такой аналог File или Path, только Path хранит путь к ресурсу в файловой системе, а URL — путь к ресурсу в интернете.

Вся магия происходит, когда мы за один вызов метода openStream() получаем сразу объект типа InputStream. Это же стандартный объект, и мы его уже изучили вдоль и поперек. Все становится очевидно уже после получения объекта типа InputStream. Ведь как вычитать из него данные, мы уже знаем.

Сравните: отличаются только две первые строчки, и то немного. Вот оно, преимущество стандартизации и работы с цепочками потоков данных:

Работа с интернетом Работа с файлом
URL url = new URL("https://javarush.com");
InputStream input = url.openStream();
byte[] buffer = input.readAllBytes();
String str = new String(buffer);
System.out.println(str);
File file = new File("c:\\readme.txt");
InputStream input = new FileInputStream(file);

byte[] buffer = input.readAllBytes();
String str = new String(buffer);
System.out.println(str);


2. Класс URLConnection

Кроме простого чтения данных из интернета, мы еще можем и загружать туда данные. Загрузка данных — это куда более сложный процесс, чем считывание. Вам понадобится на несколько методов больше. Пример:

Код Примечание
URL url = new URL("https://javarush.com");
URLConnection connection = url.openConnection();

// получили поток для отправки данных
OutputStream output = connection.getOutputStream();
output.write(1); // отправляем данные

// получили поток для чтения данных
InputStream input = connection.getInputStream();
int data = input.read(); // читаем данные
Создаем объект URL с путем к странице
Создаем двустороннее соединение


Получаем поток вывода
Выводим в него данные


Получаем поток ввода
Читаем из него данные

Обратите внимание, что тут мы больше не вызываем метод url.openStream(). Вместо этого мы идем по более длинному пути:

  • Сначала мы устанавливаем стабильное двустороннее соединение с помощью метода URLConnection openConnection()
  • Затем получаем поток для отправки данных с помощью метода connection.getOutputStream() и отправляем данные серверу
  • Затем получаем поток для чтения данных с помощью метода connection.getInputStream() и начинаем читать из него данные.

Контроль ресурсов

Строго говоря, мы должны все потоки обернуть в try-with-resources для безопасной работы. А еще не помешало бы обернуть голые InputStream и OutputStream во что-нибудь более удобное. Например, в PrintStream и BufferedReader.

Если мы все это сделаем, наш код будет выглядеть как-то так:

URL url = new URL("https://javarush.com");
URLConnection connection = url.openConnection(); // отправляем данные
try (OutputStream output = connection.getOutputStream();
   PrintStream sender = new PrintStream(output))
{
   sender.println("Привет");
}

// читаем данные
try(InputStream input = connection.getInputStream();
   BufferedReader reader = new BufferedReader(new InputStreamReader(input)))
{
   while (reader.ready())
      System.out.println(reader.readLine());
}

3. Примеры работы с сетью

А давай-ка мы что-нибудь загрузим из интернета. И не просто загрузим, а сохраним на диск.

Например, давайте напишем программу, которая сохраняет на диск картинку с главной страницы Google.

В принципе ничего сложного. В самой простой интерпретации этот код будет выглядеть так:

Сохранение файла на диск
String image = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
URL url = new URL(image);
InputStream input = url.openStream();

Path path = Path.of("c:\\GoogleLogo.png");
Files.copy(input, path);

С помощью трех первых строк мы получаем поток данных от интернет-ресурса — от картинки.

В четвертой строке мы создаем имя файла, в который будем сохранять картинку. Имя может быть любым, однако расширение файла должно совпадать с расширением картинки в интернете. Так локальные программы просмотра картинок будут правильно ее открывать.

Ну и наконец, последняя строка — это один из методов copy класса Files. У класса Files их несколько. Этот метод, который мы использовали, принимает в качестве первого параметра источник данных — байтовый поток (InputStream), а в качестве второго параметра — имя файла, куда нужно записывать данные.

Теоретически, если бы URL картинки был коротким, этот код вообще можно было бы записать в одну строку:

Копирование данных из потока в файл
Files.copy(
   new URL("https://www.google.com/logo.png").openStream(),
   Path.of("c:\\GoogleLogo.png")
);

Писать так, конечно же, не нужно, однако этот пример демонстрирует, насколько удобные и мощные в Java потоки ввода-вывода.



Комментарии (328)
  • популярные
  • новые
  • старые
Для того, чтобы оставить комментарий Вы должны авторизоваться
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:14
Спасибо JavaRush за материалы, НО здесь на мой субъективный взгляд ОЧЕНЬ не хватает информации про HttpClient (современный вариант отправки HTTP-запросов). HttpClient — это встроенный в Java инструмент для отправки HTTP-запросов и получения ответов (Java 11+). Он поддерживает: • GET, POST, PUT, DELETE и другие методы - позволяет выполнять стандартные HTTP-операции: получать данные с сервера, отправлять новые данные, изменять существующие ресурсы и удалять их. • Заголовки (Headers) - позволяют передавать дополнительную информацию в запросе: токены авторизации, тип данных, информацию о клиенте, настройки кэширования и другие параметры. • JSON в теле запроса - позволяет отправлять структурированные данные в формате JSON, который чаще всего используется при работе с REST API. • Таймауты - позволяют ограничить время ожидания ответа от сервера, чтобы приложение не зависало при медленном соединении или недоступности сервиса. • Асинхронные запросы - позволяют отправлять HTTP-запросы без блокировки основного потока. Ответ обрабатывается позже через CompletableFuture, что удобно для параллельной работы с несколькими запросами. • HTTP/2 - поддержка современного протокола передачи данных с улучшенной производительностью: мультиплексирование запросов, меньше накладных расходов и более эффективное использование соединения. HTTP-методы: • GET - получение данных с сервера. Самый частый запрос. • POST - создание новых ресурсов. Отправляет данные в теле запроса (обычно JSON). • PUT - полное обновление существующего ресурса. • PATCH - частичное обновление ресурса (меняет только указанные поля). • DELETE - удаление ресурса с сервера. • HEAD - как GET, но возвращает только заголовки без тела. Проверка существования ресурса. • OPTIONS - получение информации о поддерживаемых методах. Для CORS-настроек. • TRACE - диагностика и отладка, возвращает запрос обратно клиенту. На этом заканчиваем теорию. Открываем IntelliJ IDEA и переходим к примерам и трюкам :)
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:16
Пример №1. GET-запрос (базовый)
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws IOException, InterruptedException {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/users/octocat"))
                .GET()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        System.out.println("Ответ: " + response.body());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Построение GET-запроса 3. Отправка запроса и получение ответа 4. Вывод кода и тела ответа Когда использовать: получение данных
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:22
Пример №2. GET с заголовками (авторизация)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/user"))
                .header("Authorization", "Bearer GITHUB_TOKEN")
                .header("Accept", "application/json")
                .header("User-Agent", "MyApp/1.0")
                .GET()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        System.out.println("Ответ: " + response.body());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Формирование GET-запроса к GitHub API с добавлением HTTP-заголовков 3. Отправка GET-запроса и получение ответа 4. Вывод кода и тела ответа Когда использовать: получение данных с авторизацией P.S. Для получания GitHub-токена (GITHUB_TOKEN) необходимо выполнить след. шаги: 1. Зайти на страницу GitHub. Если здесь впервые - регистрируемся 2. GitHub-аватарка (справа сверху) → Settings → Developer settings 3. Personal access tokens → Tokens (classic) 4. Нажимаем Generate new token и настраиваем свой токен 5. После настройки нажимаем Generate token и копируем полученный токен
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:30
Пример №3. GET-запрос с параметрами в URL
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        String baseUrl = "https://api.github.com/search/repositories";
        String query = "q=" + URLEncoder.encode("java", StandardCharsets.UTF_8);
        String sort = "sort=" + URLEncoder.encode("stars", StandardCharsets.UTF_8);
        String order = "order=" + URLEncoder.encode("desc", StandardCharsets.UTF_8);
        String perPage = "per_page=" + URLEncoder.encode("5", StandardCharsets.UTF_8);

        String fullUrl = baseUrl + "?" + query + "&" + sort + "&" + order + "&" + perPage;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(fullUrl))
                .GET()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        System.out.println("Ответ: " + response.body());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Формирование базового URL GitHub API 3. Задание параметров поиска, а затем сборка полного URL с query-параметрами 4. Отправка GET-запроса и получение ответа 5. Вывод кода ответа и JSON со списком репозиториев Когда использовать: поиск, фильтрация информации по ссылке
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:33
Пример №4. POST с JSON (создание ресурса)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        String json = """
                {
                    "title": "Hello World",
                    "body": "My first blog post",
                    "userId": 1
                }
                """;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        System.out.println("Созданный пост: " + response.body());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Формирование JSON с данными поста 3. Создание POST-запроса с добавлением заголовка Content-Type 4. Отправка запроса с получением ответа 5. Вывод кода и тела ответа с созданным постом Когда использовать: создание ресурса
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:37
Пример №5. POST с JSON и заголовками (авторизация)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        String json = """
                {
                    "name": "John Doe",
                    "email": "john@example.com",
                    "role": "admin"
                }
                """;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts"))
                .header("Content-Type", "application/json")
                .header("Authorization", "Bearer test-token")
                .header("X-Request-Id", "12345")
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        System.out.println("Ответ: " + response.body());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Создание JSON с данными 3. Формирование POST-запроса с заголовками 4. Отправка запроса с получением ответа 5. Вывод кода и тела ответа от сервера Когда использовать: создание с авторизацией
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:41
Пример №6. PUT запрос (обновление ресурса)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        String json = """
                {
                    "id": 1,
                    "title": "Updated Title",
                    "body": "Updated content",
                    "userId": 1
                }
                """;

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
                .header("Content-Type", "application/json")
                .PUT(HttpRequest.BodyPublishers.ofString(json))
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        System.out.println("Обновленный пост: " + response.body());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Формирование JSON с обновленными данными 3. Создание и отправка PUT-запроса. После отправки получаем ответ 4. Вывод кода ответа и обновленного объекта в формате JSON Когда использовать: полное обновление существующего ресурса
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:47
Пример №7. DELETE запрос (удаление ресурса)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://jsonplaceholder.typicode.com/posts/1"))
                .header("Authorization", "Bearer your-token")
                .DELETE()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Статус: " + response.statusCode());
        if (response.statusCode() == 200 || response.statusCode() == 204) {
            System.out.println("Ресурс успешно удален!");
        } else {
            System.out.println("Ошибка удаления: " + response.statusCode());
        }
    }
}
Что здесь происходит: 1. Создание HTTP-клиента. 2. Формирование DELETE-запроса к ресурсу. 3. Отправка запроса на удаление. 4. Выводи кода ответа и результата операции Когда использовать: удаление данных
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:48
Пример №8. GET с таймаутом
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/users/octocat"))
                .timeout(Duration.ofSeconds(10))
                .GET()
                .build();

        try {
            HttpResponse<String> response = client.send(
                    request,
                    HttpResponse.BodyHandlers.ofString()
            );
            System.out.println("Статус: " + response.statusCode());
            System.out.println("Ответ: " + response.body());
        } catch (java.net.http.HttpTimeoutException e) {
            System.err.println("Запрос превысил таймаут!");
        }
    }
}
Что здесь происходит: 1. Создание клиента, который будет ждать установления соединения максимум 5 секунд 2. Формирование GET-запроса 3. Обработка успешного ответа 4. Вывод кода и тела ответа Когда использовать: работа с медленными API
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 15:54
Пример №9. Асинхронный GET запрос
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.CompletableFuture;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/users/octocat"))
                .GET()
                .build();

        CompletableFuture<HttpResponse<String>> future = client.sendAsync(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        System.out.println("Запрос отправлен, ждем ответ...");

        future.thenAccept(response -> {
            System.out.println("Статус: " + response.statusCode());
            System.out.println("Ответ: " + response.body());
        }).join();
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Формирование GET-запроса 3. Асинхронная отправка запроса через sendAsync() 4. Обработка ответа через CompletableFuture.thenAccept() 5. Дожидание методом join() завершения операции 6. Вывод кода и тела ответа Когда использовать: одновременная отправка большого количества запросов, потребность в построении высоконагруженных систем, работа с UI-приложениями (интерфейс не должен "зависать" во время запросов)
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:01
Пример №10. Несколько асинхронных запросов
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        List<String> urls = List.of(
                "https://api.github.com/users/octocat",
                "https://api.github.com/users/defunkt",
                "https://api.github.com/users/mojang"
        );

        System.out.println("Отправка 3 запросов параллельно...");

        List<CompletableFuture<String>> futures = urls.stream()
                .map(url -> HttpRequest.newBuilder()
                        .uri(URI.create(url))
                        .GET()
                        .build())
                .map(request -> client.sendAsync(
                        request,
                        HttpResponse.BodyHandlers.ofString()
                ))
                .map(future -> future.thenApply(response -> {
                    String login = response.body().split("\"login\":\"")[1].split("\"")[0];
                    return login + " - Статус: " + response.statusCode();
                }))
                .toList();

        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                .join();

        for (CompletableFuture<String> future : futures) {
            System.out.println(future.get());
        }
    }
}
Что здесь происходит: 1. Создание клиента и списка URL 2. Параллельная отправка GET-запросов через sendAsync() 3. Обработка ответов через thenApply() 4. Ожидание всех запросов через allOf().join() 5. Вывод результатов Когда использовать: массовые операции с параллельной загрузкой
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:04
С примерами достаточно. Теперь переходим к трюкам :)
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:08
Трюк №1. Создание клиента с настройками
import java.net.http.HttpClient;
import java.time.Duration;

public class HttpClientUtil {
    public static void main(String[] args) {
        HttpClient configuredClient = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_2)
                .connectTimeout(Duration.ofSeconds(10))
                .followRedirects(HttpClient.Redirect.NORMAL)
                .priority(1)
                .build();

        System.out.println("Клиент настроен!");
        System.out.println("Версия: " + configuredClient.version());
        System.out.println("Таймаут соединения: " + configuredClient.connectTimeout().get());
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Настройка версии HTTP, таймаута и редиректа. 3. Устанавка приоритета запроса 4. Получение информации о настройках клиента Основные настройки HTTP-клиента: • Версия HTTP-протокола: .version(HttpClient.Version.HTTP_2) - выбор версии протокола (HTTP_1_1, HTTP_2). • Таймаут подключения: .connectTimeout(Duration.ofSeconds(10)) - максимальное время ожидания соединения с сервером. • Обработка редиректов: .followRedirects(HttpClient.Redirect.NORMAL) - настройка переходов по перенаправлениям (NEVER, NORMAL, ALWAYS). • Приоритет HTTP/2 запросов: .priority(1) - установка приоритета запросов (меньшее значение — выше приоритет). • Прокси-сервер: .proxy(ProxySelector.of(...)) - настройка отправки запросов через прокси. • Аутентификатор: .authenticator(authenticator) - автоматическая передача логина и пароля при авторизации. • Управление Cookies: .cookieHandler(new CookieManager()) - хранение и передача cookies между запросами. • SSL/TLS настройки: .sslContext(sslContext) - настройка сертификатов и параметров HTTPS-соединения. • Локальный адрес подключения: .localAddress(address) - выбор локального IP-адреса или сетевого интерфейса для подключения.
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:20
Трюк №2. Проверка статуса ответа
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {
    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/users/octocat"))
                .GET()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        int statusCode = response.statusCode();

        System.out.println("Статус: " + statusCode);

        if (statusCode >= 200 && statusCode < 300) {
            System.out.println("Запрос успешен");
            System.out.println("Ответ: " + response.body());

        } else if (statusCode == 404) {
            System.out.println("Ресурс не найден");

        } else if (statusCode == 401 || statusCode == 403) {
            System.out.println("Ошибка доступа");

        } else if (statusCode >= 500) {
            System.out.println("Ошибка сервера");

        } else {
            System.out.println("Другой статус: " + statusCode);
        }
    }
}
Что здесь происходит: 1. Создание HTTP-клиента 2. Формирование GET-запроса 3. Отправка запроса и получение ответа 4. Проверка HTTP-кода ответа с выводом результата Основные коды ответов: 200 OK — успешно, данные получены 201 Created — ресурс создан 204 No Content — успешно, но тело ответа пустое 301/302 Redirect — перенаправление 400 Bad Request — ошибка в запросе 401 Unauthorized — требуется авторизация 403 Forbidden — доступ запрещен 404 Not Found — ресурс не найден 429 Too Many Requests — слишком много запросов 500 Internal Server Error — ошибка сервера
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:29
Трюк №3a. Получение всех заголовков
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;

public class HttpClientUtil {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/users/octocat"))
                .GET()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        Map<String, List<String>> headers = response.headers().map();

        System.out.println("ВСЕ ЗАГОЛОВКИ:");
        headers.forEach((name, values) ->
                System.out.println(name + ": " + String.join(", ", values)));
    }
}
Что здесь происходит: 1. Создание HTTP-клиента и GET-запроса 2. Получение ответа через send() 3. Извлечение и вывод всех заголовков
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:43
Трюк №3b. Работа с основными заголовками
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.github.com/users/octocat"))
                .GET()
                .build();

        HttpResponse<String> response = client.send(
                request,
                HttpResponse.BodyHandlers.ofString()
        );

        printHeaders(response);
        printGithubLimits(response);
        checkEtag(response);
    }

    private static void printHeaders(HttpResponse<String> response) {
        String[] headers = {"Content-Type", "Content-Length", "Date", "Server", "Cache-Control"};
        for (String header : headers) {
            System.out.println(header + ": " + response.headers()
                    .firstValue(header).orElse("Не указан"));
        }
    }

    private static void printGithubLimits(HttpResponse<String> response) {
        System.out.println("\nGitHub Rate Limits:");
        System.out.println("Лимит: " + response.headers()
                .firstValue("X-RateLimit-Limit").orElse("Не указан"));
        System.out.println("Осталось: " + response.headers()
                .firstValue("X-RateLimit-Remaining").orElse("Не указан"));
        System.out.println("Сброс: " + response.headers()
                .firstValue("X-RateLimit-Reset").orElse("Не указан"));
    }

    private static void checkEtag(HttpResponse<String> response) {
        System.out.println("\nЕсть ETag: " + response.headers()
                .firstValue("ETag").isPresent());
    }
}
Что здесь происходит: 1. Вывод заголовков, лимитов GitHub и ETag.
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 16:56
Трюк №4a. Скачивание файла через ofFile()
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.Duration;

public class HttpClientUtil {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .followRedirects(HttpClient.Redirect.NORMAL)
                .build();

        Path downloadDir = Paths.get(System.getProperty("user.home"), "Downloads");

        System.out.println("Downloading cat.png...");
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://avatars.githubusercontent.com/u/583231?v=4"))
                .header("User-Agent", "Java HttpClient")
                .GET()
                .build();

        HttpResponse<Path> response = client.send(request,
                HttpResponse.BodyHandlers.ofFile(
                        downloadDir.resolve("cat.png"),
                        StandardOpenOption.CREATE,
                        StandardOpenOption.WRITE,
                        StandardOpenOption.TRUNCATE_EXISTING
                ));

        System.out.println("Status: " + response.statusCode());
        System.out.println("Saved: " + response.body());
    }
}
Что здесь происходит: скачивание файла напрямую в папку Downloads с помощью BodyHandlers.ofFile() и перезаписью существующего файла. Подходит для прямого скачивания файлов (изображения, архивы, большие файлы, PDF, видео) без контроля работы потоков
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:03
Трюк №4b. Скачивание через InputStream
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

public class HttpClientUtil {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newHttpClient();

        Path downloadDir = Paths.get(System.getProperty("user.home"), "Downloads");

        System.out.println("Downloading google_logo.png...");
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"))
                .header("User-Agent", "Java HttpClient")
                .GET()
                .build();

        HttpResponse<InputStream> response = client.send(request,
                HttpResponse.BodyHandlers.ofInputStream());

        Path filePath = downloadDir.resolve("google_logo.png");
        try (InputStream input = response.body()) {
            Files.copy(input, filePath, StandardCopyOption.REPLACE_EXISTING);
        }

        System.out.println("Saved: " + filePath);
    }
}
Что здесь происходит: скачивание файла через BodyHandlers.ofInputStream() с ручным копированием в файл. Даёт больше контроля над процессом. Подходит для контролируемого скачивания файлов (изображения, архивы, большие файлы, PDF, видео). Контроль осуществляется в рамках потоковых операций, что является главным отличием ofInputStream от ofFile: ofFile():
HTTP
 |
 |
 v
Файл
ofInputStream():
HTTP
 |
 |
 v
InputStream
 |
 |-- обработка
 |
 v
Файл
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:13
Трюк №4c. Скачивание HTML-страницы
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.time.Duration;

public class HttpClientUtil {

    public static void main(String[] args) throws Exception {
        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(5))
                .build();

        Path downloadDir = Paths.get(System.getProperty("user.home"), "Downloads");

        System.out.println("Downloading example.html...");
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://example.com"))
                .timeout(Duration.ofSeconds(5))
                .header("User-Agent", "Java HttpClient")
                .GET()
                .build();

        HttpResponse<Path> response = client.send(request,
                HttpResponse.BodyHandlers.ofFile(
                        downloadDir.resolve("example.html"),
                        StandardOpenOption.CREATE,
                        StandardOpenOption.WRITE,
                        StandardOpenOption.TRUNCATE_EXISTING
                ));

        System.out.println("Status: " + response.statusCode());
        System.out.println("Saved: " + response.body());
    }
}
Что здесь происходит: скачивание HTML-страницы example.com с таймаутом 5 секунд и сохранением в папку Downloads. Подходит для быстрого скачивания текстового контента (HTML, JSON, XML) без лишних сложностей и с защитой от зависаний
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:39
Трюк №5a. Обработка таймаута
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpTimeoutException;
import java.time.Duration;

public class HttpClientUtil {

    public static void main(String[] args) {
        testTimeout();
    }

    public static void testTimeout() {
        try {
            HttpClient client = HttpClient.newBuilder()
                    .connectTimeout(Duration.ofSeconds(5))
                    .build();

            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://httpbin.org/delay/10"))
                    .timeout(Duration.ofSeconds(3))
                    .GET()
                    .build();

            HttpResponse<String> response = client.send(request,
                    HttpResponse.BodyHandlers.ofString());
            System.out.println("Успешно! Статус: " + response.statusCode());

        } catch (HttpTimeoutException e) {
            System.err.println("Таймаут! Сервер не отвечает");
            System.err.println("Решение: увеличить таймаут запроса");
        } catch (IOException e) {
            System.err.println("Ошибка ввода-вывода: " + e.getMessage());
        } catch (InterruptedException e) {
            System.err.println("Запрос прерван");
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            System.err.println("Ошибка: " + e.getMessage());
        }
    }
}
Что здесь происходит: отправка запроса с таймаутом 3 секунды к серверу, который специально задерживает ответ на 10 секунд. Возникает HttpTimeoutException, которая обрабатывается с рекомендацией увеличить таймаут.
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:41
Трюк №5b. Обработка ошибки подключения
import java.io.IOException;
import java.net.ConnectException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientUtil {

    public static void main(String[] args) {
        testConnectionError();
    }

    public static void testConnectionError() {
        try {
            HttpClient client = HttpClient.newHttpClient();

            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("http://localhost:9999"))
                    .GET()
                    .build();

            client.send(request, HttpResponse.BodyHandlers.ofString());

        } catch (ConnectException e) {
            System.err.println("Сервер недоступен!");
            System.err.println("Проверьте:");
            System.err.println("  - Правильность URL");
            System.err.println("  - Работает ли сервер");
            System.err.println("  - Интернет-соединение");
        } catch (IOException e) {
            System.err.println("Ошибка ввода-вывода: " + e.getMessage());
        } catch (InterruptedException e) {
            System.err.println("Запрос прерван");
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            System.err.println("Ошибка: " + e.getMessage());
        }
    }
}
Что здесь происходит: попытка подключиться к несуществующему серверу на localhost:9999. Возникает ConnectException с подсказками по устранению проблемы.
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:43
Трюк №5c. Обработка неверного URL
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpTimeoutException;
import java.time.Duration;

public class HttpClientUtil {

    public static void main(String[] args) {
        testErrors();
    }

    public static void testErrors() {
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("htps://invalid"))
                    .GET()
                    .build();
            client.send(request, HttpResponse.BodyHandlers.ofString());

        } catch (IllegalArgumentException e) {
            System.err.println("Неверный URL");
        } catch (HttpTimeoutException e) {
            System.err.println("Таймаут");
        } catch (IOException e) {
            System.err.println("Ошибка ввода-вывода: " + e.getMessage());
        } catch (InterruptedException e) {
            System.err.println("Запрос прерван");
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            System.err.println("Ошибка: " + e.getMessage());
        }
    }
}
Что здесь происходит: обработка ошибки неверного формата URL (IllegalArgumentException) с проверкой схемы http:// или https://.
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:53
Список основных исключений при работе с HttpClient: 1. HttpTimeoutException • Причина: превышено время ожидания ответа • Решение: увеличить .timeout() или .connectTimeout() 2. ConnectException • Причина: сервер недоступен или нет соединения • Решение: проверить URL и сеть 3. IllegalArgumentException • Причина: неверный URL • Решение: проверить адрес 4. IOException • Причина: ошибка чтения или записи данных • Решение: проверить путь и права доступа 5. InterruptedException • Причина: запрос был прерван • Решение: восстановить статус потока 6. SecurityException • Причина: недостаточно прав • Решение: проверить разрешения 7. IllegalStateException • Причина: некорректное состояние объекта • Решение: создать новый запрос или клиент 8. CancellationException • Причина: асинхронный запрос отменен • Решение: проверить future.isCancelled() Общий шаблон для обработки:
try {
    HttpResponse<String> response = client.send(request,
        HttpResponse.BodyHandlers.ofString());
} catch (HttpTimeoutException e) {
    // Таймаут - увеличить время ожидания
} catch (ConnectException e) {
    // Сервер недоступен - проверить сеть
} catch (IllegalArgumentException e) {
    // Неверный URL - проверить формат
} catch (IOException e) {
    // Проблемы с файлами
} catch (InterruptedException e) {
    // Прерванный запрос
    Thread.currentThread().interrupt();
} catch (Exception e) {
    // Все остальные ошибки
}
Maxim TerletskySoftware Developer в RutiSoft Corporation
25 июля, 17:56
Надеюсь, JavaRush прислушается к моему мнению и добавит хотя бы часть материала про HttpClient в свои лекции о сетевых возможностях Java. Это современный, удобный и встроенный инструмент, который активно используется в реальных проектах. Было бы здорово увидеть его в официальных материалах курса. P.S. Если не трудно, поставьте лайк за старания 👍
Grigoryvvv
Уровень 24
Expert
29 июня, 15:55
29.06.2026 / 16 уровень
Real User
Уровень 40
14 апреля, 14:13
Какое-то странное богом забытое апи. Очень сомневаюсь что кто-то когда-то будет использовать его в таком виде. ( начиналось еще вроде нормально, закончилось дичью ) 90 процентов java разработчиков будут использовать http клиенты , и нормально параметризировать запросы телом, хедерами, типами запросов и пр. , а не отправлять рандомные байты, в общем применимость 0 , зачем нужно не ясно, жирный минус Надеюсь это смотрят мейнтейнеры курса
Anonymous #3519817Работает в Банк
26 апреля, 23:38
Никто не говорит, что указанный тут метод работы с API - это best practice. Это просто тестовые задания, чтобы понимать какие есть базовые методы взаимодействия по сети.
Rei
Уровень 32
3 февраля, 19:29
По примеру из лекции
URL url = new URL("https://javarush.com");
URLConnection connection = url.openConnection(); // отправляем данные
try (OutputStream output = connection.getOutputStream();
   PrintStream sender = new PrintStream(output))
{
   sender.println("Привет");
}

// читаем данные
try(InputStream input = connection.getInputStream();
   BufferedReader reader = new BufferedReader(new InputStreamReader(input)))
{
   while (reader.ready())
      System.out.println(reader.readLine());
}
Почему нельзя reader.ready(): Для файлов ready() иногда «работает», но для сети поток может быть блокирующим. ready() → “можно читать сейчас без блокировки”, но это не конец потока. Если использовать while(reader.ready()), можно не дождаться всего ответа и потерять данные.
Rei
Уровень 32
3 февраля, 20:00
👉Правильный способ: Читаем методом readLine() до null. null → конец потока. Так мы гарантированно прочитаем весь ответ, даже если данные приходят кусками.
// Создаём объект URL, указываем адрес
        URL url = new URL("https://javarush.com");
        // Получаем объект соединения. Пока соединение не установлено.
        URLConnection connection = url.openConnection();
        // Устанавливаем, что мы будем писать в поток (POST-like)
        connection.setDoOutput(true); // включаем режим отправки данных
        // ----------- Отправка данных -----------------
        try (OutputStream output = connection.getOutputStream();  // получаем поток для отправки данных
             PrintStream sender = new PrintStream(output)) {       // оборачиваем OutputStream для удобства печати строк
            // Отправляем строку "Привет" на сервер
            // PrintStream сам добавляет \n и конвертирует в байты
            sender.println("Привет");
        }
        // ----------- Чтение данных -----------------
        try (InputStream input = connection.getInputStream();  // получаем поток данных от сервера
             BufferedReader reader = new BufferedReader(new InputStreamReader(input))) { // оборачиваем InputStream в Reader для чтения строк
            // Правильный способ читать до конца потока:
            String line;
            while ((line = reader.readLine()) != null) {  // readLine() вернёт null, когда поток закончится
                System.out.println(line);  // выводим строку на экран
            }
            // ❌ НЕ ИСПОЛЬЗУЙ reader.ready()!
            // ready() не гарантирует, что поток закончился,
            // а в сетевых соединениях может вернуть false даже если данные ещё идут,
            // что приведёт к неполному чтению ответа
Виктор
Уровень 28
19 июля 2025, 07:47
Тяжело, часто откатывюсь назад из за непонятого ранее.
Podaytesigy
Уровень 20
27 июля 2025, 11:35
Нелегко в учение, друг, легко в бою
Anonymous #3585174
Уровень 33
16 июля 2025, 18:50
Like
Alex
Уровень 22
28 июня 2025, 21:33
Тут вопрос в другом, на фига ыообще нужна эта статья, когда в прчледней строке буквально говорится, что так делать не нужно!!! Может сначала надо ПРАВИЛЬНО учить?
Alina GabidulinaРаботает в M2
25 июня 2025, 17:23
В этой лекции будто редактор совсем обленился,из последней задачи: Используй методы setDoOutput(true) и getOutputStream() класса URLConnection ладно есть пару слов про getOutputStream(), но про setDoOutput(true) ни слова, я не злюсь, но просто не понятно почему нельзя сделать также как и в других случаях таблицу с методами?
Mikhail QA Automation Engineer
5 июня 2025, 09:51
Ужасный уровень! Понимания не осталось от слова совсем!
Robert Theater actor
12 апреля 2025, 21:16
Пока самый ужасный уровень. Я зашел спустя три месяца перерыва, и вспомнил почему я так давно не заходил. После этого уровня, действительно больше не хотелось продолжать заниматься на этой платформе. Я прекрасно понимаю, что одно из важнейших умений программиста - гуглить. Но тогда зачем я заплатил за подписку? Чтобы потом уйти на другие источники?
Danya Java Developer
4 мая 2025, 19:12
зайди чекни видео из ютуба,углубись в то место в котором тебе не понятно,зайди в chatgpt и там напиши какие методы и что тебе не понятно.Тем не менее тема ввода и вывода проходится в синтаксисе java и от неё не убежишь и если ты поменяешь платформу ничего не изменится ты встретишь одно и тоже