HTTP अनुरोधों को आग और संभालने के लिए java.net.URL कनेक्शन का उपयोग कैसे करें
httprequest httpurlconnection (8)
java.net.URLConnection
का उपयोग अक्सर यहां अक्सर पूछे जाने पर किया जाता है, और ओरेकल ट्यूटोरियल इसके बारे में बहुत संक्षिप्त है।
यह ट्यूटोरियल मूल रूप से केवल एक जीईटी अनुरोध को आग लगाने और प्रतिक्रिया पढ़ने के लिए दिखाता है। यह कहीं भी नहीं समझाता है कि दूसरों के बीच इसका उपयोग कैसे करें POST अनुरोध करें, अनुरोध शीर्षलेख सेट करें, प्रतिक्रिया शीर्षलेख पढ़ें, कुकीज़ से निपटें, एक HTML फॉर्म सबमिट करें, फ़ाइल अपलोड करें आदि।
तो, मैं "उन्नत" HTTP अनुरोधों को आग और संभालने के लिए java.net.URLConnection
का उपयोग कैसे कर सकता हूं?
अद्यतन करें
जावा 9 के साथ भेजा गया नया HTTP क्लाइंट लेकिन
jdk.incubator.httpclient
नामक इनक्यूबेटर मॉड्यूल के हिस्से के रूप में। इनक्यूबेटर मॉड्यूल डेवलपर्स के हाथों में गैर-अंतिम एपीआई डालने का माध्यम है जबकि एपीआई भविष्य में रिलीज में अंतिम रूप देने या हटाने की दिशा में प्रगति करता है।
जावा 9 में, आप एक GET
अनुरोध भेज सकते हैं जैसे:
// GET
HttpResponse response = HttpRequest
.create(new URI("http://www..com"))
.headers("Foo", "foovalue", "Bar", "barvalue")
.GET()
.response();
फिर आप लौटे HttpResponse
जांच कर सकते हैं:
int statusCode = response.statusCode();
String responseBody = response.body(HttpResponse.asString());
चूंकि यह नया HTTP क्लाइंट अंदर है java.httpclient
jdk.incubator.httpclient
मॉड्यूल, आपको इस module-info.java
फ़ाइल में इस निर्भरता की घोषणा करनी चाहिए:
module com.foo.bar {
requires jdk.incubator.httpclient;
}
HTTP के साथ काम करते समय बेस क्लास HttpURLConnection
बजाय HttpURLConnection
को संदर्भित करने के लिए लगभग हमेशा अधिक उपयोगी URLConnection
(जब आप URLConnection.openConnection()
को एक HTTP यूआरएल पर पूछते हैं तो वैसे भी URLConnection
एक सारणी वर्ग है, जो कि आप वैसे भी वापस आ जाएंगे)।
फिर आप URLConnection#setDoOutput(true)
पर भरोसा करने के बजाय POST को अनुरोध विधि को सेट करने के बजाय httpURLConnection.setRequestMethod("POST")
कर सकते हैं, जो कुछ अधिक प्राकृतिक पा सकते हैं (और जो आपको अन्य अनुरोध विधियों को निर्दिष्ट करने की अनुमति देता है पुट , हटाएं , ...)।
यह उपयोगी HTTP स्थिरांक भी प्रदान करता है ताकि आप यह कर सकें:
int responseCode = httpURLConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
आप jcabi-http (मैं एक डेवलपर हूं) से जेडीकेआरक्वेट का भी उपयोग कर सकता हूं, जो आपके लिए यह सब काम करता है, HttpURLConnection को सजाने, HTTP अनुरोधों को फायर करने और प्रतिक्रियाओं को पार्स करने के लिए, उदाहरण के लिए:
String html = new JdkRequest("http://www.google.com").fetch().body();
अधिक जानकारी के लिए इस ब्लॉग पोस्ट को http://www.yegor256.com/2014/04/11/jcabi-http-intro.html : http://www.yegor256.com/2014/04/11/jcabi-http-intro.html
एसओ पर इस और अन्य प्रश्नों से प्रेरित, मैंने एक न्यूनतम ओपन सोर्स basic-http-client जो यहां पाए गए अधिकांश तकनीकों का प्रतीक है।
google-http-java-client भी एक महान ओपन सोर्स संसाधन है।
मैं भी इस प्रतिक्रिया से बहुत प्रेरित था।
मैं अक्सर उन परियोजनाओं पर हूं जहां मुझे कुछ HTTP करने की ज़रूरत है, और मैं कई तृतीय पक्ष निर्भरताओं को नहीं लेना चाहता हूं (जो दूसरों को लाता है और इसी तरह आदि)
मैंने इस बातचीत में से कुछ के आधार पर अपनी खुद की उपयोगिताएं लिखना शुरू कर दिया (कहीं भी नहीं किया गया):
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 {
फिर केवल एक गुच्छा या स्थिर तरीके हैं।
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;
}
}
फिर पोस्ट करें ...
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;
}
खैर, आप विचार समझ गए....
यहां परीक्षण हैं:
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);
}
आप बाकी को यहां पा सकते हैं:
https://github.com/RichardHightower/boon
मेरा लक्ष्य उन सामान्य चीजों को प्रदान करना है जो एक और अधिक आसान तरीके से करना चाहते हैं ....
शुरुआत में मुझे इस article गुमराह किया गया था जो HttpClient
पक्ष HttpClient
।
बाद में मुझे एहसास हुआ कि HttpURLConnection
इस article से बने रहने जा रहा है
Google ब्लॉग के अनुसार :
अपाचे HTTP क्लाइंट में एक्लेयर और फियोयो पर कम कीड़े हैं। इन रिलीज के लिए यह सबसे अच्छा विकल्प है। जिंजरब्रेड के लिए, HttpURLConnection सबसे अच्छा विकल्प है। इसका सरल एपीआई और छोटा आकार एंड्रॉइड के लिए यह बहुत अच्छा बनाता है।
पारदर्शी संपीड़न और प्रतिक्रिया कैशिंग नेटवर्क उपयोग को कम करने, गति में सुधार और बैटरी बचाने के लिए। नए अनुप्रयोगों को HttpURLConnection का उपयोग करना चाहिए; यह वह जगह है जहां हम अपनी ऊर्जा आगे बढ़ेंगे।
प्रवाह rapidvaluesolutions.com/tech_blog/… और कुछ अन्य ढेर को पढ़ने के बाद, मुझे आश्वस्त है कि HttpURLConnection
लंबे समय तक रहने के लिए जा रहा है।
HttpURLConnections
के पक्ष में कुछ एसई प्रश्न:
एचटीपीपोस्ट जावा प्रोजेक्ट में काम करता है, एंड्रॉइड में नहीं
सबसे पहले अस्वीकरण पहले: पोस्ट कोड स्निपेट सभी बुनियादी उदाहरण हैं। आपको तुच्छ IOException
s और IOException
तरह NullPointerException
, ArrayIndexOutOfBoundsException
और स्वयं को प्रबंधित करने की आवश्यकता होगी।
तैयार कर रहे हैं
हमें सबसे पहले कम से कम यूआरएल और वर्णमाला जानने की जरूरत है। पैरामीटर वैकल्पिक हैं और कार्यात्मक आवश्यकताओं पर निर्भर करते हैं।
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
प्रारूप में होना चाहिए और इसके द्वारा संयोजित किया जाना चाहिए। आप सामान्य रूप से URLEncoder#encode()
का उपयोग कर निर्दिष्ट वर्णमाला के साथ क्वेरी पैरामीटर को URL-encode भी करेंगे।
String#format()
बस सुविधा के लिए है। मैं इसे पसंद करता हूं जब मुझे स्ट्रिंग कॉन्सटेनेशन ऑपरेटर +
दो बार से अधिक की आवश्यकता होगी।
(वैकल्पिक रूप से) क्वेरी पैरामीटर के साथ HTTP GET अनुरोध को फायर करना
यह एक छोटा काम है। यह डिफ़ॉल्ट अनुरोध विधि है।
URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...
किसी भी क्वेरी स्ट्रिंग को यूआरएल के साथ संयोजित किया जाना चाहिए ?
। Accept-Charset
हेडर सर्वर को संकेत दे सकता है कि पैरामीटर एन्कोडिंग क्या कर रहे हैं। यदि आप कोई क्वेरी स्ट्रिंग नहीं भेजते हैं, तो आप Accept-Charset
शीर्षलेख को दूर छोड़ सकते हैं। यदि आपको कोई शीर्षलेख सेट करने की आवश्यकता नहीं है, तो आप URL#openStream()
शॉर्टकट विधि का भी उपयोग कर सकते हैं।
InputStream response = new URL(url).openStream();
// ...
किसी भी तरह से, यदि दूसरी तरफ एक HttpServlet
, तो इसकी doGet()
विधि को कॉल किया जाएगा और पैरामीटर HttpServletRequest#getParameter()
द्वारा उपलब्ध होंगे।
परीक्षण उद्देश्यों के लिए, आप प्रतिक्रिया शरीर को नीचे के रूप में stdout प्रिंट कर सकते हैं:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
क्वेरी पैरामीटर के साथ एक HTTP POST अनुरोध फायरिंग
URLConnection#setDoOutput()
को true
सेट करने से अनुरोध विधि को POST पर सेट किया जाता है। वेब फॉर्म के रूप में मानक HTTP पोस्ट प्रकार 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 फॉर्म जमा करना चाहते हैं, तो क्वेरी स्ट्रिंग में किसी भी <input type="hidden">
तत्वों के name=value
जोड़े को लेना न भूलें और निश्चित रूप से name=value
जोड़ी <input type="submit">
तत्व जिसे आप प्रोग्रामेटिक रूप से "प्रेस" करना चाहते हैं (क्योंकि आमतौर पर सर्वर पक्ष में इसका उपयोग किया जाता है ताकि बटन दबाया जा सके और यदि ऐसा है, तो कौन सा)।
आप प्राप्त java.net.URLConnection को HttpURLConnection
भी डाल सकते हैं और इसके बजाय इसके HttpURLConnection#setRequestMethod()
उपयोग कर सकते हैं। लेकिन अगर आप आउटपुट के लिए कनेक्शन का उपयोग करने की कोशिश कर रहे हैं तो आपको अभी भी URLConnection#setDoOutput()
को true
पर सेट करने की आवश्यकता true
।
HttpURLConnection httpConnection = (HttpURLConnection) new URL(url).openConnection();
httpConnection.setRequestMethod("POST");
// ...
किसी भी तरह से, यदि दूसरी तरफ एक HttpServlet
, तो इसकी doPost()
विधि को कॉल किया जाएगा और पैरामीटर HttpServletRequest#getParameter()
द्वारा उपलब्ध होंगे।
वास्तव में HTTP अनुरोध को फायरिंग
आप URLConnection#connect()
साथ HTTP अनुरोध को स्पष्ट रूप से आग लगा सकते हैं, लेकिन जब आप HTTP प्रतिक्रिया के बारे में कोई जानकारी प्राप्त करना चाहते हैं, तो अनुरोध को स्वचालित रूप से मांग पर निकाल दिया जाएगा, जैसे URLConnection#getInputStream()
और अन्य का उपयोग कर प्रतिक्रिया निकाय। उपर्युक्त उदाहरण वास्तव में ऐसा करते connect()
, इसलिए connect()
कॉल वास्तव में अनिवार्य है।
HTTP प्रतिक्रिया जानकारी एकत्रित करना
आपको यहां एक
HttpURLConnection
आवश्यकता है। यदि आवश्यक हो तो इसे पहले कास्ट करें।int status = httpConnection.getResponseCode();
for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) { System.out.println(header.getKey() + "=" + header.getValue()); }
जब
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 अनुरोध भेजने से पहले आपको CookiePolicy
की ACCEPT_ALL
CookieManager
साथ CookieManager
तैयार करने की आवश्यकता है।
// 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();
// ...
ध्यान दें कि यह हमेशा सभी परिस्थितियों में ठीक से काम नहीं करने के लिए जाना जाता है। यदि यह आपके लिए विफल रहता है, तो सबसे अच्छा कुकी हेडर मैन्युअल रूप से इकट्ठा करना और सेट करना है। आपको मूल रूप से लॉगिन या पहले GET
अनुरोध की प्रतिक्रिया से सभी Set-Cookie
शीर्षकों को पकड़ने की आवश्यकता है और फिर बाद के अनुरोधों के माध्यम से इसे पास करना होगा।
// 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
जैसे कि expires
, path
इत्यादि। वैकल्पिक रूप से, आप cookie.substring(0, cookie.indexOf(';'))
split()
बजाय split()
।
स्ट्रीमिंग मोड
HttpURLConnection
वास्तव में इसे भेजने से पहले पूरे अनुरोध निकाय को डिफ़ॉल्ट रूप से बफर करेगा, भले ही आपने HttpURLConnection
connection.setRequestProperty("Content-Length", contentLength);
का उपयोग कर स्वयं एक निश्चित सामग्री लंबाई निर्धारित की हो connection.setRequestProperty("Content-Length", contentLength);
। जब भी आप बड़े POST अनुरोध (जैसे फाइल अपलोड करना) भेजते हैं तो यह OutOfMemoryException
s का कारण बन सकता है। इससे बचने के लिए, आप HttpURLConnection#setFixedLengthStreamingMode()
सेट करना चाहते हैं।
httpConnection.setFixedLengthStreamingMode(contentLength);
लेकिन यदि सामग्री की लंबाई वास्तव में पहले से ज्ञात नहीं है, तो आप तदनुसार HttpURLConnection#setChunkedStreamingMode()
को सेट करके HttpURLConnection#setChunkedStreamingMode()
स्ट्रीमिंग मोड का उपयोग कर सकते हैं। यह HTTP Transfer-Encoding
हेडर को चंक करने के लिए सेट करेगा जो अनुरोध निकाय को भाग में भेजे जाने के लिए मजबूर करेगा। नीचे दिया गया उदाहरण शरीर को 1 केबी के टुकड़ों में भेज देगा।
httpConnection.setChunkedStreamingMode(1024);
उपभोक्ता अभिकर्ता
ऐसा हो सकता है कि एक अनुरोध एक अप्रत्याशित प्रतिक्रिया देता है, जबकि यह वास्तविक वेब ब्राउज़र के साथ ठीक काम करता है। सर्वर पक्ष शायद User-Agent
अनुरोध शीर्षलेख के आधार पर अनुरोध अवरुद्ध कर रहा है। URLConnection
डिफ़ॉल्ट रूप से इसे Java/1.6.0_19
सेट Java/1.6.0_19
जहां अंतिम भाग स्पष्ट रूप से Java/1.6.0_19
संस्करण है। आप इसे निम्नानुसार ओवरराइड कर सकते हैं:
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()
को पढ़ना HttpURLConnection#getErrorStream()
कि सर्वर ने कोई उपयोगी त्रुटि जानकारी भेजी है या नहीं।
InputStream error = ((HttpURLConnection) connection).getErrorStream();
यदि HTTP प्रतिक्रिया कोड -1 है, तो कनेक्शन और प्रतिक्रिया हैंडलिंग के साथ कुछ गलत हो गया है। HttpURLConnection
कार्यान्वयन पुराने HttpURLConnection
में कनेक्शन को जिंदा रखने के साथ कुछ हद तक छोटी है। आप http.keepAlive
सिस्टम प्रॉपर्टी को false
सेट करके इसे बंद करना चाहते हैं। आप अपने आवेदन की शुरुआत में प्रोग्रामेटिक रूप से ऐसा कर सकते हैं:
System.setProperty("http.keepAlive", "false");
फाइल अपलोड कर रहा है
आप आम तौर पर मिश्रित पोस्ट सामग्री (बाइनरी और वर्ण डेटा) के लिए multipart/form-data
एन्कोडिंग का उपयोग करेंगे। एन्कोडिंग 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 से पहले, आपकी सबसे अच्छी पसंद एक multipart/form-data
अनुरोध को पार्स करने के लिए अपाचे कॉमन्स फ़ाइल अपलोड का उपयोग कर रही है। FileUpload और Servelt 3.0 दृष्टिकोण दोनों के उदाहरणों के लिए यह उत्तर भी देखें।
अविश्वसनीय या गलत कॉन्फ़िगर किए गए HTTPS साइटों से निपटना
कभी-कभी आपको एक HTTPS URL कनेक्ट करने की आवश्यकता होती है, शायद इसलिए कि आप एक वेब स्क्रैपर लिख रहे हैं। उस स्थिति में, आप शायद javax.net.ssl.SSLException: Not trusted server certificate
सामना कर सकते हैं javax.net.ssl.SSLException: Not trusted server certificate
कुछ HTTPS साइट्स पर javax.net.ssl.SSLException: Not trusted server certificate
नहीं है जो अपने SSL प्रमाणपत्र को अद्यतित नहीं रखते हैं, या java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
या javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
कुछ गलत कॉन्फ़िगर किए गए HTTPS साइट्स पर javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
।
आपके वेब स्क्रैपर क्लास में निम्न एक-बार-चलने वाले 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);
}
}
आखरी श्ब्द
Apache HttpComponents HttpClient इस सब में अधिक सुविधाजनक है :)
पार्सिंग और एचटीएमएल निकालने
यदि आप चाहते हैं कि HTML से डेटा पार्सिंग और निकालना है, तो बेहतर है कि एक HTML पार्सर जैसे Jsoup का उपयोग करें
I recomend http-request built on apache http api. (I'm a developer)
Perform HTTP GET request
static final HttpRequest<String> httpRequest =
HttpRequestBuilder.createGet(someUri, String.class)
.responseDeserializer(ResponseDeserializer.ignorableDeserializer()).build();
ResponseHandler<String> responseHandler = httpRequest.execute(requestParameters);
int statusCode = responseHandler.getStatusCode();
String responseBody = responseHandler.get(); // see javadoc of get method
या
ResponseHandler<String> responseHandler =
httpRequest.executeWithQuery(queryString); //queryString example "param1=param1¶m2=param2"
Perform HTTP POST request
Replace HttpRequestBuilder.createGet
to HttpRequestBuilder.createPost
Add headers
static final HttpRequest<String> httpRequest =
HttpRequestBuilder.createGet(someUri, String.class)
.responseDeserializer(ResponseDeserializer.ignorableDeserializer())
.addDefaultHeader("Accept", "application/json")
.build();
Convert response to type
let's say response is JSON and you know it
{"name":"myname","lastname":"mylastname","age":25}
You must create class User:
public User{
private String Name;
private String Lastname;
private int Age;
// getters and setters
}
static final HttpRequest<User> httpRequest =
HttpRequestBuilder.createGet(someUri, User.class).build();
ResponseHandler<User> responseHandler = httpRequest.execute(requestParameters);
User userFromResponse = responseHandler.orElse(null); //returns null if content isn't present
System.out.print(user.getName()); //myname
Note: You don't need to worry about Exceptions. All exceptions is wrapped.