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
İlk önce Yasal Uyarı: Yayınlanan kod parçacıkları temel örnekleridir. IOException
önemsiz s işlemek gerekir ve RuntimeException
NullPointerException
, 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
HttpURLConnection
işte burada sana ihtiyacım var. İlk olarak, gerekirse sürün.
int status = httpConnection.getResponseCode();
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
System.out.println(header.getKey() "=" header.getValue());
}
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 OutOfMemoryException
s 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
Nasıl takvim Dilimleri Java kullanarak...
Nasıl düğmeye tıklama Parçaları içinde...
Nasıl indirmek ve internetten bir dosy...
"kökeni yalnızca HTTP istekleri i...
Java kullanarak Java SE server sadece ...