पहले एक अस्वीकरण पहले: पोस्ट किए गए कोड स्निपेट सभी मूल उदाहरण हैं। तुच्छ IOException
एस और RuntimeException
एस की तरह संभालना होगा NullPointerException
, ArrayIndexOutOfBoundsException
और खुद को संजोना होगा।
तैयार कर रहे हैं
हमें पहले कम से कम URL और चारसेट जानने की आवश्यकता है। पैरामीटर वैकल्पिक हैं और कार्यात्मक आवश्यकताओं पर निर्भर करते हैं।
String url = "http://example.com";
String charset = "UTF-8"; // Or in Java 7 and later, use the constant: java.nio.charset.StandardCharsets.UTF_8.name()
String param1 = "value1";
String param2 = "value2";
// ...
String query = String.format("param1=%s¶m2=%s",
URLEncoder.encode(param1, charset),
URLEncoder.encode(param2, charset));
क्वेरी मापदंडों को name=value
प्रारूप में होना चाहिए और उनके अनुरूप होना चाहिए &
। आप सामान्य रूप से उपयोग किए गए चारसेट के साथ क्वेरी पैरामीटर को URL-एनकोड भी करेंगे URLEncoder#encode()
।
String#format()
सिर्फ सुविधा के लिए है। मैं इसे पसंद करता हूं, जब मुझे स्ट्रिंग कॉन्कैटेशन ऑपरेटर की आवश्यकता +
दो बार से अधिक होगी।
HTTP GET अनुरोध (वैकल्पिक रूप से) क्वेरी मापदंडों के साथ फायरिंग
यह एक तुच्छ कार्य है। यह डिफ़ॉल्ट अनुरोध विधि है।
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
किसी भी क्वेरी स्ट्रिंग का उपयोग करके URL तक पहुंचना चाहिए ?
। Accept-Charset
शीर्ष लेख सर्वर क्या मापदंडों एन्कोडिंग में हैं संकेत हो सकता है। आप किसी भी क्वेरी स्ट्रिंग नहीं भेजते हैं, तो आप छोड़ सकते हैं Accept-Charset
हैडर दूर। यदि आपको कोई हेडर सेट करने की आवश्यकता नहीं है, तो आप URL#openStream()
शॉर्टकट विधि का उपयोग भी कर सकते हैं ।
InputStream response = new URL(url).openStream();
// ...
किसी भी तरह से, यदि दूसरा पक्ष ए है HttpServlet
, तो इसकी doGet()
विधि को बुलाया जाएगा और पैरामीटर उपलब्ध होंगे HttpServletRequest#getParameter()
।
परीक्षण के प्रयोजनों के लिए, आप नीचे दिए गए अनुसार प्रतिक्रिया निकाय को प्रिंट कर सकते हैं:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
क्वेरी पैरामीटर के साथ HTTP POST अनुरोध फायरिंग
स्थापना URLConnection#setDoOutput()
करने के लिए true
परोक्ष पोस्ट करने के लिए अनुरोध विधि सेट। वेब फॉर्म के रूप में मानक HTTP POST application/x-www-form-urlencoded
उस प्रकार का होता है जिसमें क्वेरी स्ट्रिंग अनुरोध निकाय को लिखा जाता है।
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true); // Triggers POST.
connection.setRequestProperty("Accept-Charset", charset);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
try (OutputStream output = connection.getOutputStream()) {
output.write(query.getBytes(charset));
}
InputStream response = connection.getInputStream();
// ...
नोट: जब भी आप प्रोग्राम रूप से HTML फॉर्म सबमिट करना चाहते हैं, तो name=value
किसी भी <input type="hidden">
तत्व के जोड़े को क्वेरी स्ट्रिंग में ले जाना न भूलें और निश्चित रूप name=value
से उस <input type="submit">
तत्व की जोड़ी भी जिसे आप प्रोग्रामेटिक रूप से "प्रेस" करना चाहते हैं (क्योंकि यदि बटन को दबाया गया था और यदि ऐसा है, तो कौन अलग है, यह आमतौर पर सर्वर साइड में उपयोग किया जाता है।
आप इसके बजाय प्राप्त URLConnection
का HttpURLConnection
उपयोग कर सकते हैं और इसका उपयोग कर सकते हैं HttpURLConnection#setRequestMethod()
। लेकिन अगर आप आउटपुट के लिए कनेक्शन का उपयोग करने की कोशिश कर रहे हैं तो भी आपको सेट URLConnection#setDoOutput()
करने की आवश्यकता है true
।
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
किसी भी तरह से, यदि दूसरा पक्ष ए है HttpServlet
, तो इसकी doPost()
विधि को बुलाया जाएगा और पैरामीटर उपलब्ध होंगे HttpServletRequest#getParameter()
।
वास्तव में HTTP रिक्वेस्ट को फायर करना
आप स्पष्ट रूप से HTTP अनुरोध के साथ आग लगा सकते हैं URLConnection#connect()
, लेकिन जब आप HTTP प्रतिक्रिया के बारे में कोई जानकारी प्राप्त करना चाहते हैं, जैसे कि प्रतिक्रिया निकाय का उपयोग करना URLConnection#getInputStream()
आदि, तो अनुरोध स्वचालित रूप से मांग पर निकाल दिया जाएगा । उपरोक्त उदाहरण ठीक यही करते हैं, इसलिए यह connect()
कॉल वास्तव में शानदार है।
HTTP प्रतिक्रिया जानकारी इकट्ठा करना
HTTP प्रतिक्रिया स्थिति :
आपको HttpURLConnection
यहां की जरूरत है। यदि आवश्यक हो तो पहले इसे कास्ट करें।
int status = httpConnection.getResponseCode();
HTTP प्रतिक्रिया हेडर :
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
System.out.println(header.getKey() + "=" + header.getValue());
}
HTTP प्रतिक्रिया एन्कोडिंग :
जब Content-Type
एक charset
पैरामीटर होता है , तो प्रतिक्रिया बॉडी की संभावना पाठ आधारित होती है और हम तब सर्वर-साइड निर्दिष्ट वर्ण एन्कोडिंग के साथ प्रतिक्रिया निकाय को संसाधित करना चाहते हैं।
String contentType = connection.getHeaderField("Content-Type");
String charset = null;
for (String param : contentType.replace(" ", "").split(";")) {
if (param.startsWith("charset=")) {
charset = param.split("=", 2)[1];
break;
}
}
if (charset != null) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(response, charset))) {
for (String line; (line = reader.readLine()) != null;) {
// ... System.out.println(line) ?
}
}
} else {
// It's likely binary content, use InputStream/OutputStream.
}
सत्र को बनाए रखना
सर्वर साइड सत्र आमतौर पर कुकी द्वारा समर्थित होता है। कुछ वेब प्रपत्रों के लिए आवश्यक है कि आप एक सत्र द्वारा लॉग इन और / या ट्रैक किए जाते हैं। CookieHandler
कुकीज़ को बनाए रखने के लिए आप एपीआई का उपयोग कर सकते हैं । आपको सभी HTTP अनुरोध भेजने से पहले एक के CookieManager
साथ तैयार करने की आवश्यकता है ।CookiePolicy
ACCEPT_ALL
// 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();
// ...
ध्यान दें कि यह सभी परिस्थितियों में हमेशा ठीक से काम नहीं करने के लिए जाना जाता है। यदि यह आपके लिए विफल रहता है, तो कुकी हेडर को मैन्युअल रूप से इकट्ठा करना और सेट करना सबसे अच्छा है। आपको मूल रूप Set-Cookie
से लॉगिन या पहले GET
अनुरोध की प्रतिक्रिया से सभी हेडर को हथियाने की आवश्यकता है और फिर बाद के अनुरोधों के माध्यम से इसे पारित करें।
// Gather all cookies on the first request.
URLConnection connection = new URL(url).openConnection();
List<String> cookies = connection.getHeaderFields().get("Set-Cookie");
// ...
// Then use the same cookies on all subsequent requests.
connection = new URL(url).openConnection();
for (String cookie : cookies) {
connection.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
}
// ...
split(";", 2)[0]
वहाँ कुकी गुण जो की तरह सर्वर साइड के लिए अप्रासंगिक हैं से छुटकारा पाने के है expires
, path
आदि वैकल्पिक रूप से, आप भी इस्तेमाल कर सकते हैं cookie.substring(0, cookie.indexOf(';'))
के बजाय split()
।
स्ट्रीमिंग मोड
HttpURLConnection
डिफ़ॉल्ट रूप से इच्छा बफ़र पूरे होने से पहले वास्तव में, यह भेजने यदि आप एक निश्चित सामग्री की लंबाई खुद का उपयोग कर निर्धारित किया है चाहे अनुरोध शरीर connection.setRequestProperty("Content-Length", contentLength);
। OutOfMemoryException
जब भी आप बड़े POST अनुरोध भेजते हैं (जैसे फाइलें अपलोड करना) यह तब हो सकता है । इससे बचने के लिए, आप सेट करना चाहेंगे HttpURLConnection#setFixedLengthStreamingMode()
।
httpConnection.setFixedLengthStreamingMode(contentLength);
लेकिन अगर सामग्री की लंबाई वास्तव में पहले से ज्ञात नहीं है, तो आप HttpURLConnection#setChunkedStreamingMode()
तदनुसार सेटिंग करके chunked स्ट्रीमिंग मोड का उपयोग कर सकते हैं । यह HTTP Transfer-Encoding
हेडर को सेट करेगा chunked
जो चेंक में भेजे जा रहे अनुरोध बॉडी को मजबूर करेगा। नीचे दिए गए उदाहरण से शरीर को 1KB की मात्रा में भेजा जाएगा।
httpConnection.setChunkedStreamingMode(1024);
उपभोक्ता अभिकर्ता
ऐसा हो सकता है कि एक अनुरोध एक अप्रत्याशित प्रतिक्रिया देता है, जबकि यह एक वास्तविक वेब ब्राउज़र के साथ ठीक काम करता है । सर्वर पक्ष संभवतः User-Agent
अनुरोध हेडर के आधार पर अनुरोधों को रोक रहा है । URLConnection
डिफ़ॉल्ट रूप से इच्छा यह करने के लिए सेट Java/1.6.0_19
जहां अंतिम भाग जाहिर JRE संस्करण है। आप इसे इस प्रकार से ओवरराइड कर सकते हैं:
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"); // Do as if you're using Chrome 41 on Windows 7.
हाल ही के ब्राउज़र से उपयोगकर्ता-एजेंट स्ट्रिंग का उपयोग करें ।
गलती संभालना
यदि HTTP प्रतिक्रिया कोड 4nn
(क्लाइंट त्रुटि) या 5nn
(सर्वर त्रुटि) है, तो आप यह देखने के लिए पढ़ना चाह सकते हैं कि HttpURLConnection#getErrorStream()
क्या सर्वर ने कोई उपयोगी त्रुटि जानकारी भेजी है।
InputStream error = ((HttpURLConnection) connection).getErrorStream();
यदि HTTP प्रतिक्रिया कोड -1 है, तो कनेक्शन और प्रतिक्रिया हैंडलिंग में कुछ गड़बड़ हो गई है। HttpURLConnection
कार्यान्वयन कनेक्शन को जीवित रखने के साथ कुछ हद तक गाड़ी पुराने JREs में है। आप http.keepAlive
सिस्टम गुण को सेट करके इसे बंद करना चाह सकते हैं false
। आप अपने प्रोग्राम की शुरुआत में इसे प्रोग्रामेटिक रूप से कर सकते हैं:
System.setProperty("http.keepAlive", "false");
फाइलें अपलोड कर रहा है
आप सामान्य रूप से multipart/form-data
मिश्रित POST सामग्री (बाइनरी और चरित्र डेटा) के लिए एन्कोडिंग का उपयोग करेंगे । एन्कोडिंग RFC2388 में वर्णित अधिक विवरण में है ।
String param = "value";
File textFile = new File("/path/to/file.txt");
File binaryFile = new File("/path/to/file.bin");
String boundary = Long.toHexString(System.currentTimeMillis()); // Just generate some unique random value.
String CRLF = "\r\n"; // Line separator required by multipart/form-data.
URLConnection connection = new URL(url).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
try (
OutputStream output = connection.getOutputStream();
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
) {
// Send normal param.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
writer.append(CRLF).append(param).append(CRLF).flush();
// Send text file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"textFile\"; filename=\"" + textFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); // Text file itself must be saved in this charset!
writer.append(CRLF).flush();
Files.copy(textFile.toPath(), output);
output.flush(); // Important before continuing with writer!
writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.
// Send binary file.
writer.append("--" + boundary).append(CRLF);
writer.append("Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" + binaryFile.getName() + "\"").append(CRLF);
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName(binaryFile.getName())).append(CRLF);
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
writer.append(CRLF).flush();
Files.copy(binaryFile.toPath(), output);
output.flush(); // Important before continuing with writer!
writer.append(CRLF).flush(); // CRLF is important! It indicates end of boundary.
// End of multipart/form-data.
writer.append("--" + boundary + "--").append(CRLF).flush();
}
तो दूसरी तरफ एक है HttpServlet
, तो इसकी doPost()
विधि कहा जाता हो जाएगा और भागों से उपलब्ध हो जाएगा HttpServletRequest#getPart()
(ध्यान दें, इस प्रकार नहीं getParameter()
और इतने पर!)। getPart()
हालांकि यह तरीका अपेक्षाकृत नया है, इसे सर्वलेट 3.0 (ग्लासफिश 3, टॉम्कट 7, आदि) में पेश किया गया है। सर्वलेट 3.0 से पहले, आपका सबसे अच्छा विकल्प एक अनुरोध को पार्स करने के लिए Apache Commons FileUpload का उपयोग कर रहा है multipart/form-data
। इस उत्तर को भी FileUpload और Servelt 3.0 दृष्टिकोण दोनों के उदाहरणों के लिए देखें ।
अविश्वसनीय या गलत HTTPS साइटों से निपटना
कभी-कभी आपको HTTPS URL कनेक्ट करने की आवश्यकता होती है, शायद इसलिए कि आप वेब स्क्रैपर लिख रहे हैं। उस मामले में, आप की संभावना एक का सामना कर सकते javax.net.ssl.SSLException: Not trusted server certificate
कुछ HTTPS साइटों जो अपने SSL प्रमाणपत्र अद्यतित नहीं रखता है, या एक पर java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
या javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
कुछ गलत तरह से कॉन्फ़िगर HTTPS साइटों पर।
static
आपके वेब स्क्रैपर क्लास में निम्नलिखित एक बार चलने वाला इनिशियलाइज़र HttpsURLConnection
को उन HTTPS साइटों के रूप में अधिक उदार बनाना चाहिए और इस प्रकार उन अपवादों को अब और नहीं फेंकना चाहिए।
static {
TrustManager[] trustAllCertificates = new TrustManager[] {
new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return null; // Not relevant.
}
@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {
// Do nothing. Just allow them all.
}
}
};
HostnameVerifier trustAllHostnames = new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // Just allow them all.
}
};
try {
System.setProperty("jsse.enableSNIExtension", "false");
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCertificates, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(trustAllHostnames);
}
catch (GeneralSecurityException e) {
throw new ExceptionInInitializerError(e);
}
}
आखरी श्ब्द
अपाचे HttpComponents HttpClient है बहुत अधिक यह सब में सुविधाजनक :)
HTML को पार्स करना और निकालना
यदि आप सभी चाहते हैं कि HTML से डेटा पार्स करना और निकालना है, तो बेहतर है कि Jsoup जैसे HTML पार्सर का उपयोग करें