Питання Як використовувати java.net.URLConnection для запуску та обробки HTTP-запитів


Використання java.net.URLConnection Про це досить часто запитують тут, а також Підручник з Oracle є теж Коротко про це.

Цей підручник в основному лише показує, як запустити запит GET і прочитати відповідь. Вона ніде не пояснює, як її використовувати, зокрема, виконувати запит POST, встановлювати заголовки запитів, читати заголовки відповідей, обробляти файли cookie, надсилати HTML-форму, завантажувати файл і т. Д.

Отже, як я можу використовувати java.net.URLConnection запускати та обробляти "розширені" HTTP-запити?


1762


походження




Відповіді:


По-перше, застереження про відмову: відомі фрагменти коду є основними прикладами. Вам доведеться звертатися з тривіальним IOExceptionS і 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().

The String#format() це просто для зручності. Я віддаю перевагу, коли мені потрібен оператор конкатенації рядка + більше двох разів


Стріляючи a HTTP GET запит з (необов'язково) параметрами запиту

Це тривіальне завдання. Це типовий метод запиту.

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

Будь-який рядок запиту повинен бути об'єднаний в URL, що використовує ?. The Accept-Charset заголовок може натякнути на сервер те, що кодує параметри. Якщо ви не надсилаєте будь-який рядок запиту, то ви можете залишити Accept-Charset заголовок далеко. Якщо вам не потрібно встановлювати будь-які заголовки, то ви навіть можете використовувати URL#openStream() ярлик метод.

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

У будь-якому випадку, якщо інша сторона є a HttpServlet, то його doGet() метод буде викликаний, і параметри будуть доступні на HttpServletRequest#getParameter().

Для тестування ви можете надрукувати тег відповіді на stdout, як показано нижче:

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

Стріляючи a 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");
// ...

У будь-якому випадку, якщо інша сторона є a 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 для підтримки файлів cookie. Вам потрібно підготувати a 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]);
}
// ...

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


Режим потоку

The HttpURLConnection буде за замовчуванням буфером цілий Запитувати тіло перед його надсиланням незалежно від того, чи встановили ви фіксовану довжину вмісту за допомогою connection.setRequestProperty("Content-Length", contentLength);. Це може бути причиною OutOfMemoryExceptionколи ви одночасно надсилаєте великі запити POST (наприклад, завантажуєте файли). Щоб уникнути цього, ви хочете встановити HttpURLConnection#setFixedLengthStreamingMode().

httpConnection.setFixedLengthStreamingMode(contentLength);

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

httpConnection.setChunkedStreamingMode(1024);

Агент користувача

Це може статися так запит повертає несподівану відповідь, хоча це добре працює з реальним веб-переглядачем. На стороні сервера, ймовірно, блокуються запити на основі User-Agent заголовок запиту. The 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 з a останній браузер.


Обробка помилок

Якщо код відповіді HTTP є 4nn (Помилка клієнта) або 5nn (Серверна помилка), то ви можете прочитати його HttpURLConnection#getErrorStream() щоб побачити, чи сервер надіслав будь-яку корисну інформацію про помилку.

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

Якщо коментар HTTP відповідає -1, тоді щось трапилось з обробкою з'єднання та відповіді. The 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() і так далі!). The getPart() Однак метод є відносно новим, він введений в Servlet 3.0 (Glassfish 3, Tomcat 7 і т. д.). До Servlet 3.0 ваш найкращий вибір використовується Apache Commons FileUpload для розбору a multipart/form-data запит Також див ця відповідь для прикладів підходів FileUpload і Servelt 3.0.


Робота з ненадійними або неправильно налаштованими сайтами HTTPS

Іноді вам потрібно підключити URL HTTPS, можливо, тому що ви пишете веб-скарб. У такому випадку ви, ймовірно, стикаються з javax.net.ssl.SSLException: Not trusted server certificate на деяких сайтах HTTPS, які не оновлюють свої сертифікати SSL, або a 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);
    }
}

Останні слова

The Apache HttpComponents HttpClient є багато чого більш зручно в цьому все :)


Розбір та вилучення HTML

Якщо все, що вам потрібно, це синтаксичний аналіз та вилучення даних з HTML, то краще скористайтеся HTML-аналізатором, як-от Джоуп


2526



Потрібно спочатку поставити посилання apache, щоб люди шукали рішення швидше;) - ZeissS
@ivanceras: Якщо ви не можете викинути його на основі інформації в цій відповіді, то натисніть на кнопку Ask Question кнопка у правому верхньому куті. - BalusC
@ Бріс: Будь ласка, прочитайте специфікацію. The -- частина не є частиною самої кордону. Це просто рядок сепаратора. Я відмовився від недійсного редагування. - BalusC
@BalusC дуже дякую за такий чудовий підручник. Будь ласка, включіть заголовок "Закриття потоків / підключень". Я дійсно заплутався про те, коли і з якими потоками / з'єднаннями закривати.
Сумно, що на Android це ні рекомендується використовувати Apache HttpClient зараз і HttpURLConnection жорстоко android-developers.blogspot.in/2011/09/... - yati sagade


Під час роботи з HTTP майже завжди корисно звертатися HttpURLConnection а не базовий клас URLConnection (з URLConnection це абстрактний клас, коли ви просите URLConnection.openConnection() на HTTP-URL-адресі це все, що ви повернетеся).

Тоді ви можете замість того, щоб покладатися на URLConnection#setDoOutput(true) щоб неявно встановити метод запиту на POST замість цього httpURLConnection.setRequestMethod("POST") які деякі можуть знайти більш природні (і який також дозволяє вказати інші методи запиту, такі як Випущений, ВИДАЛИТИ, ...)

Він також надає корисні константи HTTP, щоб ви могли зробити це:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

84



setDoOutPut true - це моя проблема, яка встановила мою GET на POST. Дякую - Patrick Kafka
Якщо ви намагаєтеся записати дані на поточний потік вас повинен досі встановлений setDoOutput() до true інакше викинутий виняток (навіть якщо ви setRequestMethod("POST")) Щоб бути ясним: налаштування URLConnection#setDoOutput(true) до true неявно встановлює метод запиту для POST, але встановлює httpURLConnection.setRequestMethod("POST") до POST робить ні неявно встановлений setDoOutput() до true. - Tony Chan


Натхненний цим та іншими питаннями про SO, я створив мінімальне відкрите джерело basic-http-client що втілює більшість методів, знайдені тут.

google-http-java-client також чудовий ресурс із відкритим вихідним кодом.


49



Я просто думав про те ж саме. Але також може бути приємно мати бібліотеки barebones / просту бібліотеку Java, яка використовує лише код URLConnection, який представлений тут, що включає код для більш простих методів для створення HTTP GET, POST і т. Д. Бібліотека може бути скомпільована і упакована як JAR і імпортовані / використані в коді Java або файл вихідного класу можуть бути включені в проект Java, якщо зовнішні JAR не є бажаними. Це може бути зроблено з іншими бібліотеками, такими як Apache та ін, але це більше болю в порівнянні з простою бібліотекою файлових класів за допомогою URLConnection. - David
rapidvaluesolutions.com/tech_blog/... підтримує HttpURLConnection над HttpClient - Ravindra babu


Є два варіанти, за якими можна перейти за HTTP URL Hits: GET / POST

Запит GET: -

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()));

22



Є ще багато: PUT, DELETE, HEAD, ... - user207421
Як ви можете переглянути фактичну відповідь JSON? - Surenzxx


Я пропоную вам поглянути на цей код kevinsawicki / http-request, це в основному обгортка на вершині HttpUrlConnection це набагато простіший API, якщо ви просто хочете зробити запити прямо зараз або ви можете поглянути на джерела (це не так вже й велика), щоб подивитися, як обробляються з'єднання.

Приклад: Зробити a 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);

20





Я також був дуже натхненний цією відповіддю.

Я часто працюю над проектами, в яких мені потрібно виконувати певний 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

Моя мета полягає в тому, щоб забезпечити загальні речі, які хотіли б зробити у трохи більш простий спосіб, то ....


19



Це дивно, що в doPost Метод існує а charset Параметр, який використовується для встановлення заголовка запиту, але потім дані записуються з деякою жорсткою кодуванням набору символів IO.CHARSET. Жук? - Vit Khudenko


Оновити

Новий HTTP-клієнт постачається з Java 9, але як частина   Модуль інкубатора названий jdk.incubator.httpclient. Інкубатори є модулями   це засіб для розміщення не-кінцевих API у руках розробників, поки   API наближається до завершення чи видалення в майбутньому   випуск

У Java 9 ви можете відправити a GET запит як:

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

Тоді ви можете перевірити повернуту HttpResponse:

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

Оскільки цей новий HTTP-клієнт знаходиться в java.httpclient  jdk.incubator.httpclient модуль, ви повинні оголосити цю залежність у вашому module-info.java файл:

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

15





Спочатку мене це ввели в оману стаття який сприяє HttpClient.

Пізніше я зрозумів це HttpURLConnection збирається залишитися від цього стаття

Відповідно до блогу Google:

Apache HTTP-клієнт має менше помилок на Eclair і Froyo. Це найкращий вибір для цих випусків. Для Gingerbread HttpURLConnection є найкращим вибором. Його простий API і малий розмір робить його чудово підходить для Android.

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

Після прочитання Ця стаття і якимось іншим стеком над питаннями потоку, я переконаний в цьому HttpURLConnection триватиме довше.

Деякі з питань СЕ сприяють HttpURLConnections:

На Android створіть запит POST з даними форми кодуваної форми URL без використання UrlEncodedFormEntity

HttpPost працює в проекті Java, а не в Android


14