Avatar ·

Как использовать java.net.URLConnection для отправки и обработки HTTP запросов?

Всем привет! Я новичок в Java и пытаюсь разобраться с отправкой HTTP-запросов через стандартную библиотеку. Проблема в том, что я не могу правильно настроить и обработать ответ от сервера. Вот мой код: ```java import java.net.*; import java.io.*; public class HttpTest { public static void main(String[] args) throws Exception { URL url = new URL("http://example.com/api/data"); URLConnection con = url.openConnection(); con.setDoOutput(true); // Отправка POST данных OutputStream os = con.getOutputStream(); os.write("param1=value1¶m2=value2".getBytes()); os.flush(); os.close(); // Чтение ответа BufferedReader reader = new BufferedReader( new InputStreamReader(con.getInputStream())); String line; while ((line = reader.readLine()) != null) { System.out.println(line); } reader.close(); } } ``` Проблемы: 1. Когда я запускаю этот код, он зависает на `getOutputStream()`. 2. Иногда получаю `java.net.ProtocolException: Cannot write output after reading input`. 3. Не могу понять, как установить заголовки (Content-Type, Authorization и т.д.). 4. Ответ приходит не полностью или с ошибками. Пожалуйста, объясните, как правильно работать с `URLConnection` для HTTP. Нужны примеры как для GET, так и для POST запросов. Заранее спасибо! <<>>

Правильная работа с HttpURLConnection

Ваша главная ошибка — использование абстрактного класса URLConnection вместо HttpURLConnection. Для HTTP необходимо явно приводить соединение к этому типу. Также важно соблюдать порядок действий: сначала настройка, потом запись, потом чтение.

Базовый шаблон для POST запроса

import java.net.HttpURLConnection;
import java.net.URL;
import java.io.*;

public class HttpPostExample {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://example.com/api/data");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        
        // 1. Настройка соединения
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("User-Agent", "Mozilla/5.0");
        conn.setDoOutput(true); // Разрешаем запись
        conn.setDoInput(true);  // Разрешаем чтение
        
        // 2. Отправка данных
        String params = "param1=value1¶m2=value2";
        try (OutputStream os = conn.getOutputStream()) {
            byte[] input = params.getBytes("utf-8");
            os.write(input, 0, input.length);
        }
        
        // 3. Проверка кода ответа
        int responseCode = conn.getResponseCode();
        System.out.println("Response Code: " + responseCode);
        
        // 4. Чтение ответа (учитываем ошибки)
        BufferedReader reader;
        if (responseCode >= 200 && responseCode < 300) {
            reader = new BufferedReader(
                new InputStreamReader(conn.getInputStream(), "utf-8"));
        } else {
            reader = new BufferedReader(
                new InputStreamReader(conn.getErrorStream(), "utf-8"));
        }
        
        String line;
        StringBuilder response = new StringBuilder();
        while ((line = reader.readLine()) != null) {
            response.append(line.trim());
        }
        reader.close();
        System.out.println("Response: " + response.toString());
        
        conn.disconnect();
    }
}

GET запрос

public class HttpGetExample {
    public static void main(String[] args) throws Exception {
        URL url = new URL("http://example.com/api/data?param1=value1");
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept", "application/json");
        
        int responseCode = conn.getResponseCode();
        System.out.println("Response Code: " + responseCode);
        
        if (responseCode == HttpURLConnection.HTTP_OK) {
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            
            while ((inputLine = reader.readLine()) != null) {
                response.append(inputLine);
            }
            reader.close();
            System.out.println(response.toString());
        } else {
            System.out.println("GET request failed");
        }
        conn.disconnect();
    }
}

Важные моменты

  • Порядок действий строгий: сначала настройка (setRequestMethod, setRequestProperty), потом setDoOutput, потом getOutputStream, потом getInputStream.
  • Нельзя смешивать чтение и запись: после вызова getInputStream() запись в OutputStream запрещена.
  • Всегда закрывайте потоки в блоке try-with-resources или finally.
  • Обрабатывайте коды ошибок: используйте getErrorStream() для кодов 4xx и 5xx.
  • Устанавливайте User-Agent — многие серверы блокируют запросы без этого заголовка.

Работа с JSON

conn.setRequestProperty("Content-Type", "application/json; utf-8");
conn.setRequestProperty("Accept", "application/json");

String jsonInput = "{\"key\":\"value\"}";
try (OutputStream os = conn.getOutputStream()) {
    byte[] input = jsonInput.getBytes("utf-8");
    os.write(input, 0, input.length);
}

Этот подход работает для большинства HTTP API. Для более сложных сценариев (redirects, cookies, multipart) рекомендую использовать HttpClient из Java 11+.

<<>>

Альтернатива: использование Apache HttpClient (если нужна гибкость)

Стандартный URLConnection хорош для простых запросов, но для сложных сценариев (прокси, keep-alive, автоматические редиректы) лучше использовать библиотеку Apache HttpClient.

import org.apache.http.client.methods.*;
import org.apache.http.impl.client.*;
import org.apache.http.entity.*;
import org.apache.http.util.*;

public class ApacheHttpExample {
    public static void main(String[] args) throws Exception {
        try (CloseableHttpClient client = HttpClients.createDefault()) {
            
            // POST запрос
            HttpPost post = new HttpPost("http://example.com/api/data");
            post.setHeader("Content-Type", "application/json");
            post.setEntity(new StringEntity("{\"key\":\"value\"}"));
            
            try (CloseableHttpResponse response = client.execute(post)) {
                String content = EntityUtils.toString(response.getEntity());
                System.out.println("Status: " + response.getStatusLine().getStatusCode());
                System.out.println("Response: " + content);
            }
            
            // GET запрос
            HttpGet get = new HttpGet("http://example.com/api/data?param=value");
            try (CloseableHttpResponse response = client.execute(get)) {
                String content = EntityUtils.toString(response.getEntity());
                System.out.println(content);
            }
        }
    }
}

Преимущества Apache HttpClient:

  • Автоматическое управление соединениями (пул соединений).
  • Поддержка всех HTTP методов (PUT, DELETE, PATCH).
  • Встроенная обработка редиректов и куки.
  • Потокобезопасность.

Недостаток: нужно добавлять зависимость в Maven/Gradle. Для простых проектов достаточно стандартного HttpURLConnection.