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

1611

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

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

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

Теги:
http
httprequest
urlconnection
httpurlconnection

12 ответов

2465
Лучший ответ

Прежде всего, отказ от ответственности: опубликованные фрагменты кода являются основными примерами. Вам нужно будет обрабатывать тривиальные 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-encode параметры запроса с указанной кодировкой с помощью 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().

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

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

  • Статус ответа HTTP:

    Здесь вам нужно HttpURLConnection. При необходимости отправьте его первым.

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

    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
    
  • 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 likely binary content, use InputStream/OutputStream.
    }
    

Поддержание сеанса

Сессия на стороне сервера обычно поддерживается файлом cookie. Некоторые веб-формы требуют, чтобы вы вошли в систему и/или отслеживались сеансом. Вы можете использовать API CookieHandler для поддержки файлов cookie. Вам необходимо подготовить 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 всякий раз, когда вы одновременно отправляете большие 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

Иногда вам нужно подключить URL HTTPS, возможно, потому, что вы пишете веб-скребок. В этом случае вы, вероятно, столкнетесь с 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

  • 115
    Сначала вы должны разместить ссылку на Apache, чтобы люди, которые ищут решение, нашли его быстрее;)
  • 1
    Привет BalusC, я заблудился. Не могли бы вы привести гораздо более простой пример, такой как пересылка запроса на другой сервер при сохранении URL-адреса, а также отсутствие потери данных при пересылке, таких как файлы cookie, строка URL-адреса, все остальные заголовки, такие как SOAPAction, если это когда-либо было запрос мыла, строка пользовательского агента браузера (важно не потерять по причине статистики). -Спасибо
Показать ещё 27 комментариев
76

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

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

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

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {
  • 1
    setDoOutPut true было моей проблемой, которая установила мой GET в POST. Спасибо
  • 18
    Если вы пытаетесь записать данные в выходной поток, вы все равно должны установить для setDoOutput() значение true противном случае setRequestMethod("POST") исключение (даже если вы setRequestMethod("POST") ). Для того, чтобы быть ясно: установка URLConnection#setDoOutput(true) , чтобы true неявно устанавливает метод запроса к POST, но установка httpURLConnection.setRequestMethod("POST") в POST не неявно устанавливается setDoOutput() , чтобы true .
47

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

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

  • 0
    Я просто думал так же. Но было бы также неплохо иметь простую / простую библиотеку Java, которая использует только код URLConnection, представленный здесь, который инкапсулирует код в более простые методы для выполнения HTTP GET, POST и т. Д. Затем библиотеку можно скомпилировать и упаковать как JAR и импортированные / используемые в коде Java или файле исходного кода могут быть включены в проект Java, если внешние JAR-файлы не нужны. Это может быть сделано с другими библиотеками, такими как Apache и т. Д., Но это более трудная задача по сравнению с простой библиотекой классов из 1 файла, использующей URLConnection.
  • 0
    rapidvaluesolutions.com/tech_blog/…… поддерживает HttpURLConnection, а не HttpClient
19

Есть два варианта, которые вы можете использовать с URL-адресами HTTP: 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()));
  • 4
    Есть еще несколько: PUT, DELETE, HEAD, ...
  • 2
    Как вы можете просмотреть фактический ответ JSON?
17

Я предлагаю вам взглянуть на код 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);
17

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

Я часто участвую в проектах, где мне нужно сделать 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

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

  • 2
    Странно, что в методе doPost есть параметр charset , который используется для установки заголовка запроса, но затем данные записываются с помощью некоторого жестко закодированного набора символов IO.CHARSET . Жук?
12

Update

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

В Java 9 вы можете отправить запрос 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;
}
12

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

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

В соответствии с блогом Google:

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

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

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

Некоторые из вопросов SE, благоприятствующих HttpURLConnections:

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

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

9

Вы также можете использовать 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

  • 1
    Как вы обращаетесь с куки?
8

Существует также 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

7

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

urlConnection.setDoOutput(true);
-1

Я рекомендую http-request, основанный на apache http api. (Я разработчик)

Выполнять запрос HTTP GET

static final HttpRequest<String> httpRequest =
     HttpRequestBuilder.createGet(someUri, String.class)
     .responseDeserializer(ResponseDeserializer.ignorableDeserializer()).build();

ResponseHandler<String> responseHandler = httpRequest.execute(requestParameters);

int statusCode = responseHandler.getStatusCode();
String responseBody = responseHandler.get(); // see javadoc of get method

или

 ResponseHandler<String> responseHandler = 
      httpRequest.executeWithQuery(queryString); //queryString example "param1=param1&param2=param2"

Выполните запрос HTTP POST

Замените HttpRequestBuilder.createGet на HttpRequestBuilder.createPost

Добавить заголовки

static final HttpRequest<String> httpRequest =
      HttpRequestBuilder.createGet(someUri, String.class)
           .responseDeserializer(ResponseDeserializer.ignorableDeserializer())
           .addDefaultHeader("Accept", "application/json")
           .build();

Преобразовать ответ типа

скажем, ответ JSON, и вы это знаете

{"name":"myname","lastname":"mylastname","age":25}

Вы должны создать класс User:

public User{
    private String Name;
    private String Lastname;
    private int Age;

   // getters and setters
}

static final HttpRequest<User> httpRequest =
     HttpRequestBuilder.createGet(someUri, User.class).build();

ResponseHandler<User> responseHandler = httpRequest.execute(requestParameters);
User userFromResponse = responseHandler.orElse(null); //returns null if content isn't present
System.out.print(user.getName()); //myname

Примечание. Вам не нужно беспокоиться об исключениях. Все исключения завернуты.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню