it-swarm.com.de

Verwendung von Java.net.URLConnection zum Auslösen und Behandeln von HTTP-Anforderungen

Die Verwendung von Java.net.URLConnection wird hier häufig gefragt, und das Oracle-Tutorial ist auch prägnant darüber.

In diesem Tutorial wird im Grunde nur gezeigt, wie eine GET-Anforderung ausgelöst und die Antwort gelesen wird. Es wird nirgendwo erklärt, wie es verwendet wird, um unter anderem eine POST -Anforderung auszuführen, Anforderungsheader zu setzen, Antwortheader zu lesen, mit Cookies umzugehen, ein HTML-Formular einzureichen, eine Datei hochzuladen usw.

Wie kann ich _Java.net.URLConnection_ verwenden, um "erweiterte" HTTP-Anforderungen auszulösen und zu verarbeiten?

1884
BalusC

Zuerst ein Haftungsausschluss: Die veröffentlichten Code-Schnipsel sind allesamt grundlegende Beispiele. Sie müssen mit trivialen IOExceptions und RuntimeExceptions wie NullPointerException, ArrayIndexOutOfBoundsException umgehen und sich verhalten.


Vorbereiten

Wir müssen zuerst mindestens die URL und den Zeichensatz kennen. Die Parameter sind optional und hängen von den funktionalen Anforderungen ab.

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

Die Abfrageparameter müssen im Format _name=value_ vorliegen und durch _&_ verkettet sein. Normalerweise würden Sie auch URL-codieren die Abfrageparameter mit dem angegebenen Zeichensatz mit URLEncoder#encode() .

Die String#format() dient nur zur Vereinfachung. Ich bevorzuge es, wenn ich den String-Verkettungsoperator _+_ mehr als zweimal benötige.


Auslösen einer HTTP GET -Anforderung mit (optionalen) Abfrageparametern

Es ist eine triviale Aufgabe. Dies ist die Standardanforderungsmethode.

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

Jede Abfragezeichenfolge sollte mit _?_ mit der URL verknüpft werden. Der Header Accept-Charset gibt möglicherweise einen Hinweis darauf, in welcher Codierung sich die Parameter befinden. Wenn Sie keine Abfragezeichenfolge senden, können Sie den Header _Accept-Charset_ belassen Weg. Wenn Sie keine Überschriften festlegen müssen, können Sie sogar die Methode URL#openStream() shortcut verwenden.

_InputStream response = new URL(url).openStream();
// ...
_

In beiden Fällen wird, wenn die andere Seite eine HttpServlet ist, ihre doGet() -Methode aufgerufen und die Parameter werden von HttpServletRequest#getParameter() .

Zu Testzwecken können Sie den Antworttext wie folgt auf stdout drucken:

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

Auslösen einer HTTP POST -Anforderung mit Abfrageparametern

Durch Setzen von URLConnection#setDoOutput() auf true wird die Anforderungsmethode implizit auf POST gesetzt. Das Standard-HTTP POST ist wie bei Webformularen vom Typ _application/x-www-form-urlencoded_, wobei die Abfragezeichenfolge in den Anforderungshauptteil geschrieben wird.

_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();
// ...
_

Hinweis: Wenn Sie ein HTML-Formular programmgesteuert senden möchten, vergessen Sie nicht, die _name=value_ -Paare von _<input type="hidden">_ -Elementen in die Abfragezeichenfolge und natürlich auch das _name=value_ -Paar aufzunehmen des _<input type="submit">_ -Elements, das Sie programmgesteuert "drücken" möchten (da dies normalerweise auf der Serverseite verwendet wird, um zu unterscheiden, ob und wenn ja, welche Taste gedrückt wurde).

Sie können auch die erhaltene URLConnection in HttpURLConnection umwandeln und stattdessen die HttpURLConnection#setRequestMethod() verwenden. Wenn Sie jedoch versuchen, die Verbindung für die Ausgabe zu verwenden, müssen Sie URLConnection#setDoOutput() auf true setzen.

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

In beiden Fällen wird, wenn die andere Seite eine HttpServlet ist, ihre doPost() -Methode aufgerufen und die Parameter werden von HttpServletRequest#getParameter() .


Tatsächlich wird die HTTP-Anforderung ausgelöst

Sie können die HTTP-Anforderung explizit mit URLConnection#connect() auslösen. Die Anforderung wird jedoch automatisch bei Bedarf ausgelöst, wenn Sie Informationen zur HTTP-Antwort abrufen möchten, z. B. den Antworttext mit URLConnection#getInputStream() und so weiter. Die obigen Beispiele machen genau das, so dass der Aufruf connect() in der Tat überflüssig ist.


HTTP-Antwortinformationen werden gesammelt

  1. HTTP-Antwortstatus :

    Sie benötigen ein HttpURLConnection hier. Cast es zuerst, wenn nötig.

    _int status = httpConnection.getResponseCode();
    _
  2. HTTP-Antwortheader :

    _for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
    _
  3. HTTP-Antwortcodierung :

    Wenn der _Content-Type_ einen charset-Parameter enthält, ist der Antworttext wahrscheinlich textbasiert, und wir möchten den Antworttext dann mit der serverseitig angegebenen Zeichencodierung verarbeiten.

    _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.
    }
    _

Aufrechterhaltung der Sitzung

Die serverseitige Sitzung wird normalerweise durch ein Cookie gesichert. Einige Webformulare erfordern, dass Sie angemeldet sind und/oder von einer Sitzung verfolgt werden. Sie können die CookieHandler API verwenden, um Cookies zu verwalten. Sie müssen vor dem Senden einen CookieManager mit einem CookiePolicy von ACCEPT_ALL vorbereiten alle HTTP-Anfragen.

_// 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();
// ...
_

Beachten Sie, dass dies bekanntermaßen nicht immer unter allen Umständen ordnungsgemäß funktioniert. Wenn dies für Sie fehlschlägt, ist es am besten, die Cookie-Header manuell zu erfassen und festzulegen. Grundsätzlich müssen Sie alle _Set-Cookie_ -Header aus der Antwort des Logins oder der ersten GET -Anforderung abrufen und diese dann durch die nachfolgenden Anforderungen weiterleiten.

_// 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]);
}
// ...
_

Mit der Funktion split(";", 2)[0] werden für den Server irrelevante Cookie-Attribute wie expires, path usw. entfernt. Alternativ können Sie auch cookie.substring(0, cookie.indexOf(';')) anstelle von split() verwenden.


Streaming-Modus

Der HttpURLConnection puffert standardmäßig den gesamten Anforderungshauptteil , bevor er tatsächlich gesendet wird, unabhängig davon, ob Sie selbst eine feste Inhaltslänge festgelegt haben mit connection.setRequestProperty("Content-Length", contentLength);. Dies kann zu OutOfMemoryExceptions führen, wenn Sie gleichzeitig große POST Anforderungen senden (z. B. Hochladen von Dateien). Um dies zu vermeiden, möchten Sie das HttpURLConnection#setFixedLengthStreamingMode() setzen.

_httpConnection.setFixedLengthStreamingMode(contentLength);
_

Wenn die Länge des Inhalts jedoch im Voraus nicht wirklich bekannt ist, können Sie den Chunked-Streaming-Modus nutzen, indem Sie HttpURLConnection#setChunkedStreamingMode() entsprechend einstellen. Dadurch wird der HTTP-Header Transfer-Encoding auf chunked gesetzt, wodurch der Anforderungshauptteil in Blöcken gesendet wird. Das folgende Beispiel sendet den Body in Stücken von 1 KB.

_httpConnection.setChunkedStreamingMode(1024);
_

User-Agent

Es kann vorkommen, dass eine Anfrage eine unerwartete Antwort zurückgibt, während dies mit einem echten Webbrowser gut funktioniert . Die Serverseite blockiert wahrscheinlich Anforderungen basierend auf dem Header User-Agent request. URLConnection setzt es standardmäßig auf _Java/1.6.0_19_, wobei der letzte Teil offensichtlich die JRE-Version ist. Sie können dies wie folgt überschreiben:

_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.
_

Verwenden Sie die User-Agent-Zeichenfolge aus einem aktuellen Browser .


Fehlerbehandlung

Wenn der HTTP-Antwortcode _4nn_ (Client-Fehler) oder _5nn_ (Server-Fehler) lautet, möchten Sie möglicherweise HttpURLConnection#getErrorStream() lesen, um festzustellen, ob der Server nützliche Fehlerinformationen gesendet hat.

_InputStream error = ((HttpURLConnection) connection).getErrorStream();
_

Wenn der HTTP-Antwortcode -1 ist, ist bei der Verbindungs- und Antwortverarbeitung ein Fehler aufgetreten. Die HttpURLConnection-Implementierung ist in älteren JREs etwas fehlerhaft, da die Verbindungen erhalten bleiben. Sie können es deaktivieren, indem Sie die Systemeigenschaft _http.keepAlive_ auf false setzen. Sie können dies zu Beginn Ihrer Anwendung programmgesteuert tun, indem Sie:

_System.setProperty("http.keepAlive", "false");
_

Dateien hochladen

Normalerweise verwenden Sie multipart/form-data für gemischte POST -Inhalte (Binär- und Zeichendaten). Die Codierung ist ausführlicher in RFC2388 beschrieben.

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

Wenn die andere Seite eine HttpServlet ist, wird ihre doPost() -Methode aufgerufen und die Teile werden von verfügbar sein. HttpServletRequest#getPart() (beachte also nicht getParameter() und so weiter!). Die Methode getPart() ist jedoch relativ neu, sie wurde in Servlet 3.0 (Glassfish 3, Tomcat 7 usw.) eingeführt. Vor Servlet 3.0 verwenden Sie am besten Apache Commons FileUpload , um eine _multipart/form-data_ -Anforderung zu analysieren. Siehe auch diese Antwort für Beispiele sowohl für den FileUpload- als auch den Servelt 3.0-Ansatz.


Umgang mit nicht vertrauenswürdigen oder falsch konfigurierten HTTPS-Sites

Manchmal müssen Sie eine HTTPS-URL verbinden, vielleicht weil Sie einen Web-Scraper schreiben. In diesem Fall werden Sie wahrscheinlich auf einigen HTTPS-Sites _javax.net.ssl.SSLException: Not trusted server certificate_ finden, deren SSL-Zertifikate nicht auf dem neuesten Stand sind, oder auf einigen falsch konfigurierten HTTPS-Sites _Java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found_ oder _javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name_.

Der folgende einmalige static-Initialisierer in Ihrer Web Scraper-Klasse sollte HttpsURLConnection weniger anfällig für diese HTTPS-Sites machen und daher diese Ausnahmen nicht mehr auslösen.

_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);
    }
}
_

Letzte Worte

Der Apache HttpComponents HttpClient ist in all dem viel praktischer :)


Analysieren und Extrahieren von HTML

Wenn Sie nur Daten aus HTML analysieren und extrahieren möchten, sollten Sie einen HTML-Parser wie Jsoup verwenden.

2654
BalusC

Bei der Arbeit mit HTTP ist es fast immer sinnvoller, auf HttpURLConnection zu verweisen, als auf die Basisklasse URLConnection (da URLConnection eine abstrakte Klasse ist, wenn Sie auf einem HTTP nach URLConnection.openConnection() fragen URL das ist es, was du sowieso zurück bekommst).

Dann können Sie, anstatt sich auf URLConnection#setDoOutput(true) zu verlassen, die Anforderungsmethode implizit auf POST setzen, statt httpURLConnection.setRequestMethod("POST") ausführen, was einige vielleicht natürlicher finden (und das Ihnen auch erlaubt, anzugeben) andere Anforderungsmethoden wie PUT, DELETE, ...).

Es bietet auch nützliche HTTP-Konstanten, damit Sie Folgendes tun können:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {
88

Inspiriert von dieser und anderen Fragen zu SO habe ich einen minimalen Open Source Basic-http-Client erstellt, der die meisten der hier vorkommenden Techniken verkörpert.

google-http-Java-client ist auch eine großartige Open-Source-Ressource.

50
David Chandler

Für HTTP-URL-Zugriffe stehen zwei Optionen zur Verfügung: GET/POST

GET Anfrage: -

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-Anfrage: -

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()));
23
Utkash Bhatt

Ich schlage vor, Sie werfen einen Blick auf den Code unter kevinsawicki/http-request , der im Grunde ein Wrapper über HttpUrlConnection ist und eine viel einfachere API bietet, falls Sie nur die Anforderungen stellen möchten Oder schauen Sie sich die Quellen an (sie sind nicht zu groß), um zu sehen, wie Verbindungen gehandhabt werden.

Beispiel: Erstellen Sie eine GET -Anforderung mit dem Inhaltstyp application/json und einigen Abfrageparametern:

// 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);
21
fernandohur

Aktualisieren

Der neue HTTP-Client wurde mit Java 9 ausgeliefert, jedoch als Teil eines Incubator-Moduls mit dem Namen jdk.incubator.httpclient. Mit Inkubator-Modulen können nicht endgültige APIs in die Hände der Entwickler gelegt werden, während die APIs in einer zukünftigen Version entweder finalisiert oder entfernt werden.

In Java 9 können Sie eine GET Anfrage senden wie:

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

Dann können Sie das zurückgegebene HttpResponse prüfen:

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

Seit diesem neuen HTTP-Client ist in Java.httpclient jdk.incubator.httpclient -Modul, sollten Sie diese Abhängigkeit in Ihrer module-info.Java -Datei deklarieren:

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

Diese Reaktion hat mich auch sehr inspiriert.

Ich arbeite häufig an Projekten, bei denen ich HTTP ausführen muss, und möchte möglicherweise nicht viele Abhängigkeiten von Drittanbietern einbeziehen (die andere usw. einbeziehen usw.).

Ich fing an, meine eigenen Hilfsprogramme zu schreiben, die auf einigen dieser Konversationen basierten (keine wo getan):

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 {

Dann gibt es nur ein paar oder statische Methoden.

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;
    }
}

Dann poste ...

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;
}

Na du kommst auf die Idee ....

Hier sind die Tests:

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


}

Den Rest finden Sie hier:

https://github.com/RichardHightower/boon

Mein Ziel ist es, die üblichen Dinge, die man machen möchte, ein bisschen einfacher zu machen als ...

20
RickHigh

Anfänglich wurde ich durch diesen Artikel irregeführt, der HttpClient begünstigt.

Später wurde mir klar, dass HttpURLConnection von diesem Artikel bleiben wird

Gemäß dem Google-Blog :

Der Apache HTTP-Client hat weniger Fehler bei Eclair und Froyo. Es ist die beste Wahl für diese Versionen. Für Lebkuchen ist HttpURLConnection die beste Wahl. Die einfache API und die geringe Größe machen es ideal für Android.

Transparente Komprimierung und Antwort-Caching reduzieren die Netzwerknutzung, verbessern die Geschwindigkeit und sparen Batterie. Neue Anwendungen sollten HttpURLConnection verwenden. Hier werden wir unsere Energie für die Zukunft einsetzen.

Nachdem ich diesen Artikel und einige andere Stapelüberlauffragen gelesen habe, bin ich überzeugt, dass HttpURLConnection für längere Zeiträume bleiben wird.

Einige der SE-Fragen, die HttpURLConnections begünstigen:

nter Android muss eine POST -Anforderung mit URL-codierten Formulardaten ohne Verwendung von UrlEncodedFormEntity gesendet werden.

HttpPost funktioniert in Java Projekten, nicht in Android

16
Ravindra babu

Es gibt auch OkHttp , einen standardmäßig effizienten HTTP-Client:

  • Durch die HTTP/2-Unterstützung können alle Anforderungen an denselben Host einen Socket gemeinsam nutzen.
  • Das Verbindungspooling verringert die Anforderungswartezeit (falls HTTP/2 nicht verfügbar ist).
  • Transparentes GZIP verkleinert die Download-Größen.
  • Durch das Zwischenspeichern von Antworten wird das Netzwerk für wiederholte Anforderungen vollständig umgangen.

Erstellen Sie zuerst eine Instanz von OkHttpClient:

OkHttpClient client = new OkHttpClient();

Bereiten Sie dann Ihre GET Anfrage vor:

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

verwenden Sie schließlich OkHttpClient, um vorbereitete Request zu senden:

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

Weitere Informationen finden Sie in der OkHttp-Dokumentation

14
Ali Dehghani

Sie können auch JdkRequest von jcabi-http (ich bin ein Entwickler) verwenden, das alles für Sie erledigt, HttpURLConnection dekoriert, HTTP-Anfragen auslöst und Antworten analysiert, für Beispiel:

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

Weitere Informationen finden Sie in diesem Blogbeitrag: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html

13
yegor256

wenn Sie http get verwenden, entfernen Sie diese Zeile

urlConnection.setDoOutput(true);
11