Soru HTTP isteklerini işlemek ve işlemek için java.net.URLConnection nasıl kullanılır


Kullanımı java.net.URLConnection oldukça sık sık burada sorulur ve Oracle öğreticisi olduğu çok bu konuda özlü.

Bu öğretici temel olarak bir GET isteğinin nasıl tetikleneceğini ve yanıtı nasıl okuduğunu gösterir. Başkalarının yanı sıra bir POST isteğinde bulunma, istek başlıklarını ayarlama, yanıt başlıklarını okuma, çerezlerle anlaşma, HTML formu gönderme, dosya yükleme vb.

Peki nasıl kullanabilirim java.net.URLConnection "gelişmiş" HTTP isteklerini işlemek ve işlemek için?


1762


Menşei




Cevaplar:


Öncelikle bir sorumluluk reddi beyanı: Yayınlanan kod snippet'leri tüm temel örneklerdir. Önemsiz ele almak gerekir IOExceptions ve RuntimeExceptiongibi NullPointerException, ArrayIndexOutOfBoundsException ve kendinizi korur.


hazırlama

Önce en azından URL'yi ve karakter kümesini bilmemiz gerekiyor. Parametreler isteğe bağlıdır ve fonksiyonel gereksinimlere bağlıdır.

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

Sorgu parametreleri name=value biçimlendirin ve &. Normalde sen de URL olarak kodlayın belirtilen charset ile sorgu parametreleri URLEncoder#encode().

String#format() sadece kolaylık içindir. Dize birleştirme işlecine ihtiyacım olduğunda tercih ederim + iki kereden daha fazla.


Ateş HTTP GET (isteğe bağlı) sorgu parametresiyle istek

Bu önemsiz bir görev. Bu varsayılan istek yöntemidir.

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

Herhangi bir sorgu dizesi kullanılarak URL'ye eklenmelidir. ?. Accept-Charset başlık, parametrelerini kodlayan sunucuya işaret edebilir. Herhangi bir sorgu dizisi göndermezseniz, Accept-Charset üstbilgi uzak. Herhangi bir üstbilgi ayarlamanız gerekmiyorsa, URL#openStream() kısayol yöntemi.

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

Her iki durumda, eğer diğer taraf ise HttpServletsonra doGet() yöntem çağrılacak ve parametreler tarafından kullanılabilir HttpServletRequest#getParameter().

Test amacıyla, yanıt gövdesini aşağıdaki gibi stdout'a yazdırabilirsiniz:

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

Ateş HTTP POST sorgu parametresiyle istek

ayarlamak URLConnection#setDoOutput() için true istek yöntemini POST olarak belirtir. Web formları gibi standart HTTP POST türü application/x-www-form-urlencoded sorgu dizesi istek gövdesine yazılır.

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

Not: Bir HTML formunu program aracılığıyla göndermek istediğinizde, name=value herhangi bir çift <input type="hidden"> sorgu dizesine ve tabii ki öğelere name=value çift <input type="submit"> programlı olarak "basmak" isteyeceğiniz eleman (bu, genellikle bir tuşa basıldığında ve eğer öyleyse, hangisinin hangisi olduğunu ayırt etmek için sunucu tarafında kullanılmıştır).

Ayrıca elde edilenleri de yayınlayabilirsiniz URLConnection için HttpURLConnection ve kullan HttpURLConnection#setRequestMethod() yerine. Ancak bağlantıyı bağlantı için kullanmaya çalışıyorsanız hala ayarlamanız gerekir URLConnection#setDoOutput() için true.

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

Her iki durumda, eğer diğer taraf ise HttpServletsonra doPost() yöntem çağrılacak ve parametreler tarafından kullanılabilir HttpServletRequest#getParameter().


Aslında HTTP isteğini ateşleme

HTTP isteğini açıkça URLConnection#connect()Ancak, yanıt verme gövdesi gibi HTTP yanıtıyla ilgili herhangi bir bilgi almak istediğinizde istek otomatik olarak talep üzerine tetiklenir. URLConnection#getInputStream()ve bunun gibi. Yukarıdaki örnekler tam olarak böyle yapar, connect() çağrı aslında gereksizdir.


HTTP yanıt bilgilerinin toplanması

  1. HTTP yanıt durumu:

    Bir ihtiyacın var HttpURLConnection İşte. Gerekirse önce yayınla.

    int status = httpConnection.getResponseCode();
    
  2. HTTP yanıtı üstbilgileri:

    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
    
  3. HTTP yanıtı kodlaması:

    Ne zaman Content-Type içerir charset parametresi, daha sonra yanıt gövdesi muhtemelen metin tabanlıdır ve yanıt gövdesini sunucu kodlu karakter kodlamasıyla işlemek isteriz.

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

Seansın sürdürülmesi

Sunucu tarafı oturumu genellikle bir çerez tarafından desteklenir. Bazı web formları, oturum açtığınızı ve / veya bir oturum tarafından izlendiğinizi gerektirir. Kullanabilirsiniz CookieHandler Çerezleri korumak için API. Bir tane hazırlamalısın CookieManager Birlikte CookiePolicy arasında ACCEPT_ALL Tüm HTTP isteklerini göndermeden önce.

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

Bunun her koşulda her zaman düzgün çalışmadığı biliniyor. Eğer sizin için başarısız olursa, o zaman en iyisi çerez başlıklarını elle toplamak ve ayarlamaktır. Temelde hepsini almalısın Set-Cookie girişin yanıtından başlıklar veya ilk GET istek ve daha sonra gelen istekler aracılığıyla bunu iletin.

// 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] Sunucu tarafı için ilgisiz olan çerez özelliklerinden kurtulmak için expires, pathvb. Alternatif olarak, ayrıca kullanabilirsiniz cookie.substring(0, cookie.indexOf(';')) yerine split().


Akış modu

HttpURLConnection varsayılan olarak tampon tüm Kendinizi kullanarak sabit bir içerik uzunluğunu ayarladığınızdan bağımsız olarak, aslında göndermeden önce connection.setRequestProperty("Content-Length", contentLength);. Bu neden olabilir OutOfMemoryExceptionEşzamanlı olarak büyük POST istekleri gönderdiğinizde (örneğin, dosya yükleme). Bunu önlemek için, HttpURLConnection#setFixedLengthStreamingMode().

httpConnection.setFixedLengthStreamingMode(contentLength);

Ancak içerik uzunluğu gerçekten önceden bilinmediyse, o zaman HttpURLConnection#setChunkedStreamingMode() buna göre. Bu HTTP'yi ayarlayacaktır Transfer-Encoding üstbilgi chunked istek gövdesinin parçalar halinde gönderilmesini zorlar. Aşağıdaki örnek, gövdeyi 1 KB'lik parçalara gönderir.

httpConnection.setChunkedStreamingMode(1024);

User-Agent

Olabilir bu olabilir Gerçek bir web tarayıcısıyla sorunsuz çalışırken bir istek beklenmeyen bir yanıt döndürür. Sunucu tarafı büyük olasılıkla istekleri User-Agent istek başlığı. URLConnection varsayılan olarak Java/1.6.0_19 Son bölüm açıkça JRE versiyonu. Bunu aşağıdaki gibi geçersiz kılabilirsiniz:

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.

Kullanıcı Aracısı dizesini son tarayıcı.


Hata işleme

HTTP yanıt kodu 4nn (Müşteri Hatası) veya 5nn (Sunucu Hatası), daha sonra okumak isteyebilirsiniz HttpURLConnection#getErrorStream() sunucunun herhangi bir yararlı hata bilgisi göndermiş olduğunu görmek için.

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

HTTP yanıt kodu -1 ise, bağlantı ve yanıt işleme ile bir şeyler ters gitti. HttpURLConnection Uygulama, eski JRE'lerde bağlantıların canlı kalmasıyla ilgili bir parçadır. Bunu ayarlayarak kapatmak isteyebilirsiniz. http.keepAlive sistem özelliği false. Bunu programsal olarak uygulamanızın başlangıcında yapabilirsiniz:

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

Dosya yükleniyor

Normalde kullanırsın multipart/form-data karışık POST içeriği için kodlama (ikili ve karakter verileri). Kodlama daha ayrıntılı olarak açıklanmıştır. 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();
}

Diğer tarafı ise HttpServletsonra doPost() yöntem çağrılacak ve parçalar tarafından mevcut olacak HttpServletRequest#getPart() (not, böylece değil  getParameter() ve bunun gibi!). getPart() Ancak yöntem nispeten yeni olup, Servlet 3.0'da (Glassfish 3, Tomcat 7, vb.) tanıtılmıştır. Servlet 3.0'dan önce, en iyi seçiminiz Apache Commons FileUpload ayrıştırmak multipart/form-data istek. Ayrıca bkz. bu cevap FileUpload ve Servelt 3.0 yaklaşımlarının örnekleri için.


Güvenilir olmayan veya yanlış yapılandırılmış HTTPS siteleriyle uğraşmak

Bazen bir web tarayıcısı yazdığınız için bir HTTPS URL'si bağlamanız gerekir. Bu durumda, muhtemelen bir javax.net.ssl.SSLException: Not trusted server certificate SSL sertifikalarını güncel tutmayan bazı HTTPS sitelerinde veya java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found veya javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name bazı yanlış yapılandırılmış HTTPS sitelerinde.

Aşağıdaki bir kerelik çalıştırma static web kazıyıcı sınıfında başlatıcı HttpsURLConnection Bu HTTPS siteleri ile ilgili daha fazla hoşgörüsüz ve böylece artık bu istisnaları atmıyor.

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

Son sözler

Apache HttpComponents HttpClient olduğu çok tüm bu daha uygun :)


Ayrıştırma ve HTML ayıklama

İstediğiniz şey HTML'den ayrıştırma ve veri ayıklama yapıyorsa, daha iyi bir HTML ayrıştırıcı kullanın. Jsoup


2526



Önce apache bağlantısını yerleştirmelisin, böylece bir çözüm arayan insanlar daha hızlı buluyorlar;) - ZeissS
@ivanceras: Eğer bu cevaptaki bilgilere dayanarak kaynatmıyorsanız, lütfen basın Ask Question sağ üstteki düğme. - BalusC
@Brais: Lütfen özellikleri okuyun. -- kısım sınırın kendisinin bir parçası değildir. Bu sadece bir ayırıcı dizgidir. Geçersiz düzenlemenizi geri aldım. - BalusC
@BalusC mükemmel bir öğretici için çok teşekkürler. Lütfen ayrıca "Akımların / bağlantıların kapatılması" gibi bir başlık ekleyin. Ne zaman ve hangi akışların / bağlantıların kapanacağı konusunda gerçekten kafam karıştı.
Üzgün ​​kısım, Android'de ki değil Apache'yi kullanmanız önerilir HttpClient şimdi ve HttpURLConnection zalimdir. android-developers.blogspot.in/2011/09/... - yati sagade


HTTP ile çalışırken hemen hemen her zaman daha yararlıdır HttpURLConnection temel sınıftan ziyade URLConnection (dan beri URLConnection sorduğunuzda soyut bir sınıftır URLConnection.openConnection() Yine de geri alacağınız bir HTTP URL'sinde.

O zaman yerine güvenebilirsiniz URLConnection#setDoOutput(true) istek yöntemini örtülü olarak ayarlamak için POST yerine yapmak httpURLConnection.setRequestMethod("POST") Bazıları daha doğal bulabilirler (ve aynı zamanda diğer istek yöntemlerini belirtmenizi sağlar. KOYMAK, SİL...).

Ayrıca, yararlı HTTP sabitleri sağlar, böylece şunları yapabilirsiniz:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

84



setDoOutPut true, GET'imi POST olarak ayarlayan benim sorunumdu. Teşekkürler - Patrick Kafka
Eğer çıkışa veri yazmayı deniyorsanız şart hala ayarlandı setDoOutput() için true aksi halde bir istisna atılır (siz bile setRequestMethod("POST")). Açık olmak gerekirse: URLConnection#setDoOutput(true) için true istek yöntemini örtülü olarak POST olarak ayarlar, ancak httpURLConnection.setRequestMethod("POST") POST yapar değil örtülü olarak ayarlanmış setDoOutput() için true. - Tony Chan


Bu ve SO hakkındaki diğer sorulardan esinlenerek, en az bir açık kaynak oluşturdum Temel-http-istemci Burada bulunan tekniklerin çoğunu içerir.

google-http-java-istemci aynı zamanda harika bir açık kaynak kodudur.


49



Ben de aynısını düşünüyordum. Ancak, burada bir HTTP GET, POST, vb. Yapmak için daha basit yöntemlere kod koyan, yalnızca URLConnection kodunu kullanan bir barebone / basit bir Java kütüphanesine sahip olmak da güzel olabilir. Kütüphane daha sonra JAR olarak derlenebilir ve paketlenebilir. Java kodunda veya kaynak sınıf dosyasında içe aktarılan / kullanılanlar, harici JAR'lar istenmiyorsa Java projesine dahil edilebilir. Bu Apache, vb gibi diğer kütüphaneler ile yapılabilir, ancak URLConnection kullanarak basit bir 1 dosya sınıfı kütüphanesi ile karşılaştırıldığında daha acıdır. - David
rapidvaluesolutions.com/tech_blog/... HttpClient üzerinde HttpURLConnection yanadır - Ravindra babu


URL URL Hits: GET / POST ile gidebileceğiniz 2 seçenek vardır.

GET İsteği: -

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 isteği: -

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



Birkaç tane daha var: PUT, DELETE, HEAD, ... - user207421
Gerçek JSON yanıtını nasıl görebilirsin? - Surenzxx


Kod üzerinde bir göz atmanızı öneririm kevinsawicki / http istek, onun temelde üstüne bir sarıcı HttpUrlConnection Yalnızca şu anda istekte bulunmak istediğinizde veya bağlantıların nasıl ele alındığına bakmak için kaynaklara (çok büyük değil) bakmak istediğinizde çok daha basit bir API sağlar.

Örnek: Bir GET içerik türü ile istek application/json ve bazı sorgu parametreleri:

// 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





Bu tepkiden de çok etkilendim.

Sık sık bazı HTTP yapmak zorunda olduğum projelerde yer alıyorum ve çok fazla 3. taraf bağımlılığı (başkalarını da beraberinde getirecek, vb.) Getirmek istemeyeceğim.

Bu konuşmanın bazılarına dayanarak kendi yardımcı programımı yazmaya başladım (herhangi bir yerde değil):

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 {

Sonra sadece bir demet ya da statik yöntemler var.

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

Sonra gönder ...

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

Peki fikri aldın ....

İşte testler:

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


}

Geri kalanını burada bulabilirsiniz:

https://github.com/RichardHightower/boon

Amacım, birisinin daha kolay bir şekilde yapmak isteyeceği ortak şeyleri sağlamaktır.


19



Bu garip doPost yöntem var bir charset param, bu istek başlığını ayarlamak için kullanılır, ancak daha sonra veriler bazı kodlanmış karakterlerle yazılır. IO.CHARSET. Bir böcek? - Vit Khudenko


Güncelleştirme

Yeni HTTP İstemcisi, Java 9 ile birlikte gönderildi ancak bir   Kuluçka modülü jdk.incubator.httpclient. İnkübatör modülleri   nihai olmayan API'leri geliştiricilerin ellerine koyma aracı   API'ler, bir gelecekte sonuçlandırmaya veya kaldırmaya doğru ilerler   serbest bırakmak.

Java 9'da bir GET istek gibi:

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

Sonra geri döndü inceleyebilirsiniz HttpResponse:

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

Bu yeni HTTP İstemcisi olduğu için java.httpclient  jdk.incubator.httpclient modül, bu bağımlılığı sizin module-info.java dosya:

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

15





Başlangıçta bunu yanıldım makale hangi yanadır HttpClient.

Daha sonra fark ettim ki HttpURLConnection bundan kalacağım makale

Google blogu uyarınca:

Apache HTTP istemcisinin Eclair ve Froyo'da daha az hatası vardır. Bu sürümler için en iyi seçimdir. Gingerbread için HttpURLConnection en iyi seçimdir. Basit API'si ve küçük boyutu, Android için mükemmel uyum sağlar.

Şeffaf sıkıştırma ve yanıt önbellekleme ağ kullanımını azaltır, hızı artırır ve pil tasarrufu sağlar. Yeni uygulamalar HttpURLConnection kullanmalıdır; bizim enerjimizi ileriye doğru harcayacağımız yer.

Okuduktan sonra Bu makale ve akış soruları üzerinde diğer bazı yığın, ben ikna oldum HttpURLConnection uzun süreler boyunca kalacak.

SE sorularından bazıları HttpURLConnections:

Android'de, UrlEncodedFormEntity kullanmadan URL Kodlanmış Form verileriyle bir POST isteği yapın

HttpPost, Android'de değil, Java projesinde çalışır


14