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

Использование java.net.URLConnection здесь часто задают вопрос, и руководство по Oracle слишком лаконично.

Этот учебник в основном показывает только, как запустить запрос GET и прочитать ответ. Он нигде не объясняет, как его использовать, среди прочего, для выполнения запроса POST, установки заголовков запросов, чтения заголовков ответов, работы с файлами cookie, отправки формы HTML, загрузки файла и т. Д.

Итак, как я могу использовать java.net.URLConnection запускать и обрабатывать "продвинутые" HTTP-запросы?

12 ответов

Решение

Сначала откажитесь от ответственности: все опубликованные фрагменты кода являются основными примерами. Вам нужно будет справиться с тривиальным IOException с и RuntimeException как NullPointerException , ArrayIndexOutOfBoundsException и поддерживает себя.


Подготовка

Сначала нам нужно знать хотя бы URL и кодировку. Параметры являются необязательными и зависят от функциональных требований.

String url = "http://example.com";
String charset = "UTF-8";  // Or in Java 7 and later, use the constant: java.nio.charset.StandardCharsets.UTF_8.name()
String param1 = "value1";
String param2 = "value2";
// ...

String query = String.format("param1=%s&param2=%s", 
     URLEncoder.encode(param1, charset), 
     URLEncoder.encode(param2, charset));

Параметры запроса должны быть в name=value форматировать и объединять &, Обычно вы также URL-кодируете параметры запроса с указанным набором символов, используя URLEncoder#encode(),

String#format() это просто для удобства. Я предпочитаю, когда мне нужен оператор конкатенации строк + более чем в два раза.


Запуск HTTP GET- запроса с (опционально) параметрами запроса

Это тривиальная задача. Это метод запроса по умолчанию.

URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...

Любая строка запроса должна быть присоединена к URL с помощью ?, Accept-Charset заголовок может подсказывать серверу, в какой кодировке находятся параметры. Если вы не отправляете строку запроса, вы можете оставить Accept-Charset Заголовок прочь. Если вам не нужно устанавливать какие-либо заголовки, вы можете даже использовать URL#openStream() ярлык метод.

InputStream response = new URL(url).openStream();
// ...

В любом случае, если другая сторона HttpServlet тогда его doGet() метод будет вызван и параметры будут доступны HttpServletRequest#getParameter(),

В целях тестирования вы можете напечатать тело ответа на стандартный вывод, как показано ниже:

try (Scanner scanner = new Scanner(response)) {
    String responseBody = scanner.useDelimiter("\\A").next();
    System.out.println(responseBody);
}

Запуск HTTP POST- запроса с параметрами запроса

Настройка URLConnection#setDoOutput() в true неявно устанавливает метод запроса в POST. Стандартный HTTP POST, как и веб-формы, имеет тип application/x-www-form-urlencoded причем строка запроса записывается в тело запроса.

URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);

try (OutputStream output = connection.getOutputStream()) {
    output.write(query.getBytes(charset));
}

InputStream response = connection.getInputStream();
// ...

Примечание: всякий раз, когда вы хотите отправить HTML-форму программно, не забудьте взять name=value пары любых <input type="hidden"> элементы в строке запроса и, конечно, также name=value пара <input type="submit"> элемент, который вы хотите "нажать" программно (потому что он обычно используется на стороне сервера, чтобы различать, была ли нажата кнопка, и если да, то какая).

Вы также можете разыграть полученный URLConnection в HttpURLConnection и использовать его HttpURLConnection#setRequestMethod() вместо. Но если вы пытаетесь использовать соединение для вывода, вам все равно нужно установить URLConnection#setDoOutput() в true,

HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...

В любом случае, если другая сторона HttpServlet тогда его doPost() метод будет вызван и параметры будут доступны HttpServletRequest#getParameter(),


На самом деле запускает HTTP-запрос

Вы можете запустить HTTP-запрос явно с URLConnection#connect(), но запрос будет автоматически выполняться по требованию, когда вы хотите получить какую-либо информацию об HTTP-ответе, например, тело ответа, используя URLConnection#getInputStream() и так далее. Приведенные выше примеры делают именно это, поэтому connect() звонок на самом деле лишний.


Сбор информации ответа HTTP

  1. Статус ответа HTTP:

    Тебе необходимо HttpURLConnection Вот. Примените это сначала, если необходимо.

    int status = httpConnection.getResponseCode();
    
  2. Заголовки HTTP-ответа:

    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
    
  3. Кодировка ответа HTTP:

    Когда Content-Type содержит charset параметр, тогда тело ответа, скорее всего, основано на тексте, и мы бы хотели обработать тело ответа с указанной на стороне сервера кодировкой символов.

    String contentType = connection.getHeaderField("Content-Type");
    String charset = null;
    
    for (String param : contentType.replace(" ", "").split(";")) {
        if (param.startsWith("charset=")) {
            charset = param.split("=", 2)[1];
            break;
        }
    }
    
    if (charset != null) {
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset))) {
            for (String line; (line = reader.readLine()) != null;) {
                // ... System.out.println(line) ?
            }
        }
    } else {
        // It's likely binary content, use InputStream/OutputStream.
    }
    

Ведение сессии

Сеанс на стороне сервера обычно поддерживается файлом cookie. Некоторые веб-формы требуют, чтобы вы вошли в систему и / или отслеживались сеансом. Вы можете использовать CookieHandler API для поддержки куки. Вам нужно подготовить CookieManager с CookiePolicy из ACCEPT_ALL перед отправкой всех HTTP-запросов.

// First set the default cookie manager.
CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));

// All the following subsequent URLConnections will use the same cookie manager.
URLConnection connection = new URL(url).openConnection();
// ...

connection = new URL(url).openConnection();
// ...

connection = new URL(url).openConnection();
// ...

Обратите внимание, что известно, что это не всегда работает должным образом при любых обстоятельствах. Если у вас ничего не получится, лучше всего вручную собрать и установить заголовки файлов cookie. Вам в основном нужно захватить все Set-Cookie заголовки из ответа логина или первого GET запрос, а затем передать это через последующие запросы.

// Gather all cookies on the first request.
URLConnection connection = new URL(url).openConnection();
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
// ...

// Then use the same cookies on all subsequent requests.
connection = new URL(url).openConnection();
for (String cookie : cookies) {
    connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
}
// ...

split(";", 2)[0] есть ли избавиться от атрибутов cookie, которые не имеют отношения к стороне сервера, как expires, path и т. д. Как вариант, вы также можете использовать cookie.substring(0, cookie.indexOf(';')) вместо split(),


Потоковый режим

HttpURLConnection по умолчанию будет буферизовать все тело запроса перед его отправкой, независимо от того, установили ли вы фиксированную длину контента, используя connection.setRequestProperty("Content-Length", contentLength);, Это может привести к OutOfMemoryException s всякий раз, когда вы одновременно отправляете большие запросы POST (например, загружаете файлы). Чтобы избежать этого, вы хотели бы установить HttpURLConnection#setFixedLengthStreamingMode(),

httpConnection.setFixedLengthStreamingMode(contentLength);

Но если длина контента на самом деле не известна заранее, вы можете использовать режим потоковой передачи по частям, установив HttpURLConnection#setChunkedStreamingMode() соответственно. Это установит HTTP Transfer-Encoding заголовок к chunked что заставит тело запроса отправляться кусками. Приведенный ниже пример отправит тело кусками по 1 КБ.

httpConnection.setChunkedStreamingMode(1024);

User-Agent

Может случиться, что запрос возвращает неожиданный ответ, в то время как он отлично работает с реальным веб-браузером. Серверная сторона, вероятно, блокирует запросы на основе User-Agent заголовок запроса. URLConnection по умолчанию установит его Java/1.6.0_19 где последняя часть, очевидно, является версией JRE. Вы можете переопределить это следующим образом:

connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); // Do as if you're using Chrome 41 on Windows 7.

Используйте строку User-Agent из недавнего браузера.


Обработка ошибок

Если код ответа HTTP 4nn (Ошибка клиента) или 5nn (Ошибка сервера), тогда вы можете прочитать HttpURLConnection#getErrorStream() чтобы увидеть, отправил ли сервер какую-либо полезную информацию об ошибке.

InputStream error = ((HttpURLConnection) connection).getErrorStream();

Если код ответа HTTP равен -1, значит что-то пошло не так с обработкой соединения и ответа. HttpURLConnection Реализация в старых JRE несколько глючит из-за сохранения соединений. Вы можете отключить его, установив http.keepAlive системное свойство для false, Вы можете сделать это программно в начале вашего приложения:

System.setProperty("http.keepAlive", "false");

Загрузка файлов

Вы обычно используете multipart/form-data кодирование для смешанного содержимого POST (двоичные и символьные данные). Кодирование более подробно описано в RFC2388.

String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);

try (
    OutputStream output = connection.getOutputStream();
    PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
) {
    // Send normal param.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
    writer.append(CRLF).append(param).append(CRLF).flush();

    // Send text file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
    writer.append(CRLF).flush();
    Files.copy(textFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // Send binary file.
    writer.append("--" + boundary).append(CRLF);
    writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
    writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
    writer.append("Content-Transfer-Encoding: binary").append(CRLF);
    writer.append(CRLF).flush();
    Files.copy(binaryFile.toPath(), output);
    output.flush(); // Important before continuing with writer!
    writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.

    // End of multipart/form-data.
    writer.append("--" + boundary + "--").append(CRLF).flush();
}

Если другая сторона HttpServletтогда его doPost() метод будет вызван и части будут доступны HttpServletRequest#getPart() (обратите внимание, таким образом, не getParameter() и так далее!). getPart() метод, однако, относительно новый, он введен в Servlet 3.0 (Glassfish 3, Tomcat 7 и т. д.). До Servlet 3.0 ваш лучший выбор - использовать Apache Commons FileUpload для анализа multipart/form-data запрос. Также посмотрите этот ответ для примеров подходов FileUpload и Servelt 3.0.


Работа с ненадежными или неправильно настроенными HTTPS-сайтами

Иногда вам нужно подключить HTTPS URL, возможно, потому что вы пишете веб-скребок. В этом случае вы можете столкнуться с javax.net.ssl.SSLException: Not trusted server certificate на некоторых сайтах HTTPS, которые не поддерживают свои сертификаты SSL в актуальном состоянии, или java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found или же javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name на некоторых неправильно настроенных сайтах HTTPS.

Следующий одноразовый прогон static инициализатор в вашем классе веб-скребка должен сделать HttpsURLConnection более снисходительны в отношении этих сайтов HTTPS и, следовательно, больше не выбрасывают эти исключения.

static {
    TrustManager[] trustAllCertificates = new TrustManager[] {
        new X509TrustManager() {
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null; // Not relevant.
            }
            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // Do nothing. Just allow them all.
            }
            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Do nothing. Just allow them all.
            }
        }
    };

    HostnameVerifier trustAllHostnames = new HostnameVerifier() {
        @Override
        public boolean verify(String hostname, SSLSession session) {
            return true; // Just allow them all.
        }
    };

    try {
        System.setProperty("jsse.enableSNIExtension", "false");
        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, trustAllCertificates, new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
    }
    catch (GeneralSecurityException e) {
        throw new ExceptionInInitializerError(e);
    }
}

Последние слова

Apache HttpComponents HttpClient намного удобнее во всем этом:)


Разбор и извлечение HTML

Если все, что вам нужно, это анализировать и извлекать данные из HTML, то лучше использовать HTML-парсер, такой как Jsoup

При работе с HTTP почти всегда полезнее обращаться к HttpURLConnection а не базовый класс URLConnection (поскольку URLConnection абстрактный класс, когда вы просите URLConnection.openConnection() на HTTP-URL это то, что вы все равно вернетесь).

Тогда вы можете вместо того, чтобы полагаться на URLConnection#setDoOutput(true) неявно установить метод запроса в POST вместо httpURLConnection.setRequestMethod("POST") что некоторые могут найти более естественным (и который также позволяет вам указать другие методы запроса, такие как PUT, DELETE,...).

Он также предоставляет полезные константы HTTP, так что вы можете сделать:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

Вдохновленный этим и другими вопросами о SO, я создал минимальный базовый http-клиент с открытым исходным кодом, который воплощает большинство методов, найденных здесь.

https://code.google.com/p/google-http-java-client/ также является отличным ресурсом с открытым исходным кодом.

Я предлагаю вам взглянуть на код в https://github.com/kevinsawicki/http-request, в основном это оболочка поверх HttpUrlConnection он предоставляет гораздо более простой API на тот случай, если вы просто захотите сделать запросы прямо сейчас или вы можете взглянуть на источники (они не слишком большие), чтобы взглянуть на то, как обрабатываются соединения.

Пример: сделать GET запрос с типом контента application/json и некоторые параметры запроса:

// GET http://google.com?q=baseball%20gloves&size=100
String response = HttpRequest.get("http://google.com", true, "q", "baseball gloves", "size", 100)
        .accept("application/json")
        .body();
System.out.println("Response was: " + response);

Есть 2 варианта, которые вы можете использовать с HTTP URL Hits: GET / POST

ПОЛУЧИТЬ запрос:-

HttpURLConnection.setFollowRedirects(true); // defaults to true

String url = "https://name_of_the_url";
URL request_url = new URL(url);
HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection();
http_conn.setConnectTimeout(100000);
http_conn.setReadTimeout(100000);
http_conn.setInstanceFollowRedirects(true);
System.out.println(String.valueOf(http_conn.getResponseCode()));

POST запрос:-

HttpURLConnection.setFollowRedirects(true); // defaults to true

String url = "https://name_of_the_url"
URL request_url = new URL(url);
HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection();
http_conn.setConnectTimeout(100000);
http_conn.setReadTimeout(100000);
http_conn.setInstanceFollowRedirects(true);
http_conn.setDoOutput(true);
PrintWriter out = new PrintWriter(http_conn.getOutputStream());
if (urlparameter != null) {
   out.println(urlparameter);
}
out.close();
out = null;
System.out.println(String.valueOf(http_conn.getResponseCode()));

Обновить

Новый HTTP-клиент поставляется с Java 9, но как часть модуля инкубатора с именем jdk.incubator.httpclient, Модули инкубатора - это средство, позволяющее API-интерфейсам получить финальную версию в руках разработчиков, в то время как API-интерфейсы продвигаются к завершению или удалению в будущем выпуске.

В Java 9 вы можете отправить GET запрос как:

// GET
HttpResponse response = HttpRequest
    .create(new URI("http://www.stackru.com"))
    .headers("Foo", "foovalue", "Bar", "barvalue")
    .GET()
    .response();

Затем вы можете изучить возвращенный HttpResponse:

int statusCode = response.statusCode();
String responseBody = response.body(HttpResponse.asString());

Так как этот новый HTTP-клиент находится в java.httpclientjdk.incubator.httpclient модуль, вы должны объявить эту зависимость в вашем module-info.java файл:

module com.foo.bar {
    requires jdk.incubator.httpclient;
}

Я также был очень вдохновлен этим ответом.

Я часто нахожусь в проектах, где мне нужно сделать какой-то HTTP, и я, возможно, не хочу вносить много сторонних зависимостей (которые влекут за собой других и так далее, и так далее, и т. Д.)

Я начал писать свои собственные утилиты, основанные на некоторых из этого разговора (а не где-нибудь):

package org.boon.utils;


import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Map;

import static org.boon.utils.IO.read;

public class HTTP {

Тогда есть только куча или статические методы.

public static String get(
        final String url) {

    Exceptions.tryIt(() -> {
        URLConnection connection;
        connection = doGet(url, null, null, null);
        return extractResponseString(connection);
    });
    return null;
}

public static String getWithHeaders(
        final String url,
        final Map<String, ? extends Object> headers) {
    URLConnection connection;
    try {
        connection = doGet(url, headers, null, null);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}

public static String getWithContentType(
        final String url,
        final Map<String, ? extends Object> headers,
        String contentType) {
    URLConnection connection;
    try {
        connection = doGet(url, headers, contentType, null);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}
public static String getWithCharSet(
        final String url,
        final Map<String, ? extends Object> headers,
        String contentType,
        String charSet) {
    URLConnection connection;
    try {
        connection = doGet(url, headers, contentType, charSet);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}

Тогда пост...

public static String postBody(
        final String url,
        final String body) {
    URLConnection connection;
    try {
        connection = doPost(url, null, "text/plain", null, body);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}

public static String postBodyWithHeaders(
        final String url,
        final Map<String, ? extends Object> headers,
        final String body) {
    URLConnection connection;
    try {
        connection = doPost(url, headers, "text/plain", null, body);
        return extractResponseString(connection);
    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }
}



public static String postBodyWithContentType(
        final String url,
        final Map<String, ? extends Object> headers,
        final String contentType,
        final String body) {

    URLConnection connection;
    try {
        connection = doPost(url, headers, contentType, null, body);


        return extractResponseString(connection);


    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }


}


public static String postBodyWithCharset(
        final String url,
        final Map<String, ? extends Object> headers,
        final String contentType,
        final String charSet,
        final String body) {

    URLConnection connection;
    try {
        connection = doPost(url, headers, contentType, charSet, body);


        return extractResponseString(connection);


    } catch (Exception ex) {
        Exceptions.handle(ex);
        return null;
    }


}

private static URLConnection doPost(String url, Map<String, ? extends Object> headers,
                                    String contentType, String charset, String body
                                    ) throws IOException {
    URLConnection connection;/* Handle output. */
    connection = new URL(url).openConnection();
    connection.setDoOutput(true);
    manageContentTypeHeaders(contentType, charset, connection);

    manageHeaders(headers, connection);


    IO.write(connection.getOutputStream(), body, IO.CHARSET);
    return connection;
}

private static void manageHeaders(Map<String, ? extends Object> headers, URLConnection connection) {
    if (headers != null) {
        for (Map.Entry<String, ? extends Object> entry : headers.entrySet()) {
            connection.setRequestProperty(entry.getKey(), entry.getValue().toString());
        }
    }
}

private static void manageContentTypeHeaders(String contentType, String charset, URLConnection connection) {
    connection.setRequestProperty("Accept-Charset", charset == null ? IO.CHARSET : charset);
    if (contentType!=null && !contentType.isEmpty()) {
        connection.setRequestProperty("Content-Type", contentType);
    }
}

private static URLConnection doGet(String url, Map<String, ? extends Object> headers,
                                    String contentType, String charset) throws IOException {
    URLConnection connection;/* Handle output. */
    connection = new URL(url).openConnection();
    manageContentTypeHeaders(contentType, charset, connection);

    manageHeaders(headers, connection);

    return connection;
}

private static String extractResponseString(URLConnection connection) throws IOException {
/* Handle input. */
    HttpURLConnection http = (HttpURLConnection)connection;
    int status = http.getResponseCode();
    String charset = getCharset(connection.getHeaderField("Content-Type"));

    if (status==200) {
        return readResponseBody(http, charset);
    } else {
        return readErrorResponseBody(http, status, charset);
    }
}

private static String readErrorResponseBody(HttpURLConnection http, int status, String charset) {
    InputStream errorStream = http.getErrorStream();
    if ( errorStream!=null ) {
        String error = charset== null ? read( errorStream ) :
            read( errorStream, charset );
        throw new RuntimeException("STATUS CODE =" + status + "\n\n" + error);
    } else {
        throw new RuntimeException("STATUS CODE =" + status);
    }
}

private static String readResponseBody(HttpURLConnection http, String charset) throws IOException {
    if (charset != null) {
        return read(http.getInputStream(), charset);
    } else {
        return read(http.getInputStream());
    }
}

private static String getCharset(String contentType) {
    if (contentType==null)  {
        return null;
    }
    String charset = null;
    for (String param : contentType.replace(" ", "").split(";")) {
        if (param.startsWith("charset=")) {
            charset = param.split("=", 2)[1];
            break;
        }
    }
    charset = charset == null ?  IO.CHARSET : charset;

    return charset;
}

Ну, вы поняли....

Вот тесты:

static class MyHandler implements HttpHandler {
    public void handle(HttpExchange t) throws IOException {

        InputStream requestBody = t.getRequestBody();
        String body = IO.read(requestBody);
        Headers requestHeaders = t.getRequestHeaders();
        body = body + "\n" + copy(requestHeaders).toString();
        t.sendResponseHeaders(200, body.length());
        OutputStream os = t.getResponseBody();
        os.write(body.getBytes());
        os.close();
    }
}


@Test
public void testHappy() throws Exception {

    HttpServer server = HttpServer.create(new InetSocketAddress(9212), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();

    Thread.sleep(10);


    Map<String,String> headers = map("foo", "bar", "fun", "sun");

    String response = HTTP.postBodyWithContentType("http://localhost:9212/test", headers, "text/plain", "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));


    response = HTTP.postBodyWithCharset("http://localhost:9212/test", headers, "text/plain", "UTF-8", "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));

    response = HTTP.postBodyWithHeaders("http://localhost:9212/test", headers, "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));


    response = HTTP.get("http://localhost:9212/test");

    System.out.println(response);


    response = HTTP.getWithHeaders("http://localhost:9212/test", headers);

    System.out.println(response);

    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));



    response = HTTP.getWithContentType("http://localhost:9212/test", headers, "text/plain");

    System.out.println(response);

    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));



    response = HTTP.getWithCharSet("http://localhost:9212/test", headers, "text/plain", "UTF-8");

    System.out.println(response);

    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));

    Thread.sleep(10);

    server.stop(0);


}

@Test
public void testPostBody() throws Exception {

    HttpServer server = HttpServer.create(new InetSocketAddress(9220), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();

    Thread.sleep(10);


    Map<String,String> headers = map("foo", "bar", "fun", "sun");

    String response = HTTP.postBody("http://localhost:9220/test", "hi mom");

    assertTrue(response.contains("hi mom"));


    Thread.sleep(10);

    server.stop(0);


}

@Test(expected = RuntimeException.class)
public void testSad() throws Exception {

    HttpServer server = HttpServer.create(new InetSocketAddress(9213), 0);
    server.createContext("/test", new MyHandler());
    server.setExecutor(null); // creates a default executor
    server.start();

    Thread.sleep(10);


    Map<String,String> headers = map("foo", "bar", "fun", "sun");

    String response = HTTP.postBodyWithContentType("http://localhost:9213/foo", headers, "text/plain", "hi mom");

    System.out.println(response);

    assertTrue(response.contains("hi mom"));
    assertTrue(response.contains("Fun=[sun], Foo=[bar]"));

    Thread.sleep(10);

    server.stop(0);


}

Вы можете найти отдых здесь:

https://github.com/RichardHightower/boon

Моя цель - предоставить общие вещи, которые хотелось бы сделать, немного проще, чем....

Первоначально я был введен в заблуждение этой статьей, которая одобряет HttpClient,

Позже я понял, что HttpURLConnection собирается остаться от этой статьи

Согласно блогу Google:

У HTTP-клиента Apache меньше ошибок в Eclair и Froyo. Это лучший выбор для этих релизов. Для пряников HttpURLConnection - лучший выбор. Его простой API и небольшой размер отлично подходят для Android.

Прозрачное сжатие и кэширование ответов сокращают использование сети, улучшают скорость и экономят заряд батареи. Новые приложения должны использовать HttpURLConnection; это то место, где мы будем тратить энергию вперёд.

После прочтения этой статьи и некоторых других вопросов по стеку я убежден, что HttpURLConnection собирается остаться на более длительный срок.

Некоторые из вопросов SE в пользу HttpURLConnections:

В Android сделайте POST-запрос с данными в кодированной форме URL без использования UrlEncodedFormEntity

HttpPost работает в проекте Java, а не в Android

Существует также OkHttp, который является HTTP-клиентом, который работает по умолчанию:

  • Поддержка HTTP/2 позволяет всем запросам к одному хосту совместно использовать сокет.
  • Пул соединений уменьшает задержку запроса (если HTTP/2 недоступен).
  • Прозрачный GZIP сжимает размеры загрузки.
  • Кэширование ответов полностью исключает повторные запросы в сети.

Сначала создайте экземпляр OkHttpClient:

OkHttpClient client = new OkHttpClient();

Затем подготовьте GET запрос:

Request request = new Request.Builder()
      .url(url)
      .build();

наконец, используйте OkHttpClient отправить подготовленным Request:

Response response = client.newCall(request).execute();

Для более подробной информации, вы можете обратиться к документации OkHttp

Если вы используете http get, удалите эту строку

urlConnection.setDoOutput(true);

Вы также можете использовать JdkRequest из jcabi-http (я разработчик), который выполняет всю эту работу за вас, декорирует HttpURLConnection, запускает HTTP-запросы и анализирует ответы, например:

String html = new JdkRequest("http://www.google.com").fetch().body();

Проверьте этот блог для получения дополнительной информации: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html

Если вы используете Java 11 ( за исключением Android), вместо устаревшего класса HttpUrlConnection вы можете использовать новый HTTP Client API Java 11 .

Пример GET- запроса:

      var uri = URI.create("https://httpbin.org/get?age=26&isHappy=true");
var client = HttpClient.newHttpClient();
var request = HttpRequest
        .newBuilder()
        .uri(uri)
        .header("accept", "application/json")
        .GET()
        .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());

Тот же запрос выполняется асинхронно:

      var responseAsync = client
        .sendAsync(request, HttpResponse.BodyHandlers.ofString())
        .thenApply(HttpResponse::body)
        .thenAccept(System.out::println);
// responseAsync.join(); // Wait for completion

Пример POST- запроса:

      var request = HttpRequest
        .newBuilder()
        .uri(uri)
        .version(HttpClient.Version.HTTP_2)
        .timeout(Duration.ofMinutes(1))
        .header("Content-Type", "application/json")
        .header("Authorization", "Bearer fake")
        .POST(BodyPublishers.ofString("{ title: 'This is cool' }"))
        .build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString());

Для отправки данных формы как составных ( multipart/form-data) или в кодировке URL ( application/x-www-form-urlencoded) см. это решение .

См. эту статью для примеров и дополнительной информации о клиентском API HTTP.

Другие вопросы по тегам