SORU
8 Mayıs 2010, CUMARTESİ


Java kullanarak.net.Ateş ve işlemek için URLConnection HTTP istekleri

*17* kullanımı oldukça burada sık sık sorulan ve Oracle tutorialçokbu konuda kısa ve öz.

Bu eğitim temelde sadece bir GET isteği ateş ve yanıtı okumak için nasıl gösterir. Bu diğerleri arasında bir POST isteği gerçekleştirmek için kullanın, istek başlıklarını ayarlayın, yanıt başlıkları oku, kurabiye ile başa çıkmak, bir HTML Formu, bir dosya, vb yüklemek için her yerde açıklamıyor.

Nasıl "ileri" bir isteğin var mı? HTTP java.net.URLConnection ateş ve işlemek için kullanabilir miyim yani

CEVAP
8 Mayıs 2010, CUMARTESİ


İlk önce Yasal Uyarı: Yayınlanan kod parçacıkları temel örnekleridir. IOExceptionönemsiz s işlemek gerekir ve RuntimeExceptionNullPointerException, ArrayIndexOutOfBoundsException gibi kendini eşler.


Hazırlanıyor

Öncelikle en azından URL ve karakter bilmek gerekir. Parametreler isteğe bağlıdır ve fonksiyonel ihtiyaçlarına bağlı.

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¶m2=%s", 
     URLEncoder.encode(param1, charset), 
     URLEncoder.encode(param2, charset));

Sorgu parametreleri name=value biçiminde olması ve & ile birleştirilmiş. Normalde de 110 ** belirtilen karakter kümesi URLEncoder#encode() kullanarak sorgu parametreleri.

String#format() sadece kolaylık için. Dize birleştirme operatörü iki kat daha fazla ihtiyacım olacak zaman tercih ederim.


(İsteğe bağlı olarak) sorgu parametreleri ile HTTP GET isteği ateş

Önemsiz bir görev. Varsayılan istek yöntemi.

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

Herhangi bir sorgu dize URL ? kullanılarak birleştirilmiş. Accept-Charset üstbilgi parametreleri kodlama ne sunucu ipucu olabilir. Eğer herhangi bir sorgu dize göndermek yok eğer doğru değilse, o zaman Accept-Charset Başlığı terk edebilirsiniz. Eğer herhangi bir başlık ayarlamak için ihtiyacınız varsa, o zaman bile URL#openStream() kısayol yöntemi kullanabilirsiniz.

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

Eğer diğer tarafı ise her iki şekilde de, HttpServlet doGet() yöntemi çağrılır ve parametreleri HttpServletRequest#getParameter() tarafından kullanılabilir.


Sorgu parametreleri ile HTTP POST isteği ateş

true URLConnection#setDoOutput() ayar örtülü olarak YAZILAN istek yöntemini ayarlar. Web formları gibi standart HTTP POST tür sorgu dizesi isteği yazılır application/x-www-form-urlencoded neyin organıdı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: ne zaman istersen gönder bir HTML Formu Program aracılığıyla, unutma al name=value çiftleri <input type="hidden"> öğeleri içine sorgu dizesi ve tabii ki de name=value çift <input type="submit"> element hangisi hoşuna gider "basın" aracılığıyla (çünkü genelde kullanılan sunucu tarafı ayırt etmek için bir düğme basılı ve eğer öyleyse, hangisi).

Ayrıca HttpURLConnection URLConnection elde edilen dökme ve HttpURLConnection#setRequestMethod() onun yerine kullanabilirsiniz. Ama eğer çıkış bağlantısı kullanmaya çalışıyorsanız hala true ** 123 kurmamız gerekiyor.

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

Eğer diğer taraftan bir ya da HttpServlet doPost() yöntemi çağrılır ve parametreleri 126 ** tarafından kullanılabilir.


Aslında ateş HTTP isteği

Sen-ebilmek ateş HTTP isteği açıkça URLConnection#connect(), ama bu isteği otomatik olarak ateş üzerinde talep istediğinizde herhangi bir bilgi hakkında HTTP yanıt gibi bir yanıt vücut kullanarak URLConnection#getInputStream(). Yukarıdaki örnekler tam olarak bunu yapıyor, connect() çağrı aslında gereksiz.


HTTP yanıtı bilgi toplama

1) HTTP response status:

HttpURLConnection işte burada sana ihtiyacım var. İlk olarak, gerekirse sürün.

int status = httpConnection.getResponseCode();

2) HTTP response headers:

for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
    System.out.println(header.getKey()   "="   header.getValue());
}

3) HTTP response encoding:

Content-Type charset bir parametre içeriyorsa, o zaman yanıt gövde muhtemelen metin tabanlı ve sunucu tarafında belirtilen karakter sonra kodlama ile yanıt gövde işlemek istiyoruz.

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

Oturum bakımı

Sunucu tarafı oturumu genellikle bir kurabiye tarafından desteklenmektedir. Bazı web formları ve/veya Oturum bir oturum tarafından takip edilmekte olduğunu gerektirir. Çerezleri korumak için CookieHandler API kullanabilirsiniz. Tüm HTTP istekleri göndermeden önce ACCEPT_ALL CookiePolicy CookieManager bir hazırlamak gerekir.

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

Bu her zaman düzgün, her koşulda çalışması için bilinen olduğunu unutmayın. Eğer başarısız olursa, o zaman en iyisi el ile toplamak ve çerez başlıkları ayarlamak için. Temelde açma veya cevap GET ilk isteği Set-Cookie tüm başlıkları kapmak ve sonraki istekleri ile bu sonra geçmesi gerekiyor.

// 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] alakasız cookie nitelikler kurtulmak için expires, path, vb gibi sunucu tarafı için. Alternatif olarak, aynı zamanda split() yerine cookie.substring(0, cookie.indexOf(';')) kullanabilirsiniz.


Streaming

HttpURLConnection varsayılan arabellektümistek göndermeden önce, sabit bir içerik uzunluğu belirlediğiniz olsun connection.setRequestProperty("Content-Length", contentLength); kullanarak kendinizi ne olursa olsun vücut. Bu, aynı anda büyük POST istekleri (örneğin dosya yükleme) göndermek zaman OutOfMemoryExceptions neden olabilir. Bunu önlemek için, HttpURLConnection#setFixedLengthStreamingMode() ayarlamak istiyorum.

httpConnection.setFixedLengthStreamingMode(contentLength);

Ama eğer içerik uzunluğu çok önceden belli değilse, o zaman ona göre HttpURLConnection#setChunkedStreamingMode() ayarlayarak yığın halinde akış modu kullanabilirsiniz. Bu HTTP Transfer-Encoding başlık istek parçalar halinde gönderilen vücut zorlayacak 82 ** ayarlayın. Aşağıdaki örnek, 1 KB parçaları vücut gönderecek.

httpConnection.setChunkedStreamingMode(1024);

User-Agent

Bir istek gerçek bir web tarayıcı ile gayet iyi çalışıyor beklenmeyen bir yanıt verir, bu durumda olabilir. Sunucu tarafında muhtemelen User-Agent istek başlığı dayalı istekleri engelliyor. Varsayılan olarak URLConnection son haliyle TOTEM sürümü olduğu Java/1.6.0_19 olarak ayarlayın. Aşağıdaki gibi bu 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.

recent browser bir Kullanıcı Aracısı dizesi kullanın.


Hata işleme

Eğer HTTP yanıt kodu 4nn (İstemci Hatası) veya 5nn (Sunucu Hatası), o zaman isteyebilirsiniz okuma HttpURLConnection#getErrorStream() eğer server var gönderilen herhangi bir yararlı bilgi hatası.

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

Eğer HTTP yanıt kodu -1, daha sonra ise bir bağlantı ile yanlış ve işleme yanıt gitti. HttpURLConnection uygulama eski JREs bağlantıları canlı tutmak biraz adamcağız. false http.keepAlive sistem özelliğini ayarlayarak devre dışı bırakmak isteyebilirsiniz. Bu uygulama ile başlayan Program aracılığıyla yapabilirsiniz:

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

Dosyaları yüklemek

Normalde karışık YAZI içeriği (ikili ve karakter veri) multipart/form-data kodlama kullanmak istiyorum. Kodlama daha fazla ayrıntı RFC2388 nitelendirdi.

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 HttpServlet doPost() yöntemi çağrılır ve parçaları 147 ** tarafından sunulacak. (böylece notdeğilgetParameter() ve daha pek çoğu!). getPart() yöntem ancak oldukça yeni, Sunucu uygulaması 3.0 (7, vb Tomcat 3, Önemli) tanıttı. Önceki 3.0, en iyi seçim Sunucu uygulaması için Apache Commons FileUpload multipart/form-data isteği ayrıştırmak için kullanıyor. Ayrıca FileUpload ve Servelt 3.0 yaklaşımları her iki örnek için this answer bkz.


Güvenilir olmayan ya da yanlış ile ilgili siteler HTTPS

Bazen bir web kazıyıcı yazdığın için HTTPS URL, belki de bağlamanız gerekir. Bu durumda, olabilir, muhtemelen bir yüz javax.net.ssl.SSLException: Not trusted server certificate bazı HTTPS sitelerinin bilmeyen tutmak kendi SSL sertifikaları güncel, ya da bir java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name bazı yanlış HTTPS siteleri.

Aşağıdaki web kazıyıcı sınıf static başlatıcı HttpsURLConnection bu HTTPS sitelere daha hoşgörülü olun ve bu özel durumlar, artık atmak değil dolayısıyla gerektiği zaman çalıştırın.

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çokhepsi bu:) daha kullanışlıdır


HTML ayrıştırma ve ayıklanması

İsterseniz tüm HTML ve veri ayrıştırma, ayıklama, sonra daha iyi Jsoup gibi bir HTML çözümleyici kullanın

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • max2sims2

    max2sims2

    19 Kasım 2008
  • multimediaGEEKS LLC

    multimediaGE

    3 Mayıs 2010
  • Nightmare2005

    Nightmare200

    14 Ocak 2007