আগে একটি দাবি অস্বীকার: পোস্ট কোড স্নিপেট সমস্ত মৌলিক উদাহরণ। আপনি তুচ্ছ হ্যান্ডেল করতে হবে IOException
s এবং RuntimeException
মত গুলি NullPointerException
, ArrayIndexOutOfBoundsException
এবং নিজেকে স্ত্রীদেরকে।
প্রস্তুতি
আমাদের প্রথমে কমপক্ষে ইউআরএল এবং চারসেটটি জানতে হবে। পরামিতিগুলি alচ্ছিক এবং কার্যকরী প্রয়োজনীয়তার উপর নির্ভর করে।
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 জিইটি অনুরোধ ফায়ার করা
এটি একটি তুচ্ছ কাজ। এটি ডিফল্ট অনুরোধ পদ্ধতি।
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()
।
পরীক্ষার উদ্দেশ্যে, আপনি নীচের মত প্রতিক্রিয়া বডি প্রসারিত করতে পারেন:
try (Scanner scanner = new Scanner(response)) {
String responseBody = scanner.useDelimiter("\\A").next();
System.out.println(responseBody);
}
ক্যোয়ারী পরামিতিগুলির সাথে একটি HTTP পোস্ট অনুরোধ ফায়ার করা
সেট URLConnection#setDoOutput()
থেকে true
পরোক্ষভাবে পোষ্ট করতে অনুরোধ পদ্ধতি সেট করে। ওয়েব ফর্মগুলির মতো স্ট্যান্ডার্ড এইচটিটিপি পোস্টটি 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();
// ...
দ্রষ্টব্য: আপনি যখনই প্রোগ্রামটিমে কোনও এইচটিএমএল ফর্ম জমা দিতে চান, তখন 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()
।
আসলে এইচটিটিপি অনুরোধ চালানো
আপনি এইচটিটিপি অনুরোধকে স্পষ্টভাবে ফায়ার করতে পারেন URLConnection#connect()
তবে আপনি এইচটিটিপি প্রতিক্রিয়া সম্পর্কিত কোনও তথ্য পেতে চাইলে যেমন রেসপন্স বডি ব্যবহার করে ইত্যাদি অনুরোধটি স্বয়ংক্রিয়ভাবে চাহিদা অনুসারে বরখাস্ত হয়ে যাবে 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
কুকিজ বজায় রাখতে API ব্যবহার করতে পারেন । আপনি একটি প্রস্তুতির প্রয়োজন CookieManager
একটি সঙ্গে CookiePolicy
এর ACCEPT_ALL
সব HTTP অনুরোধ পাঠানোর আগে।
// 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
যখনই আপনি একযোগে বড় পোস্টের অনুরোধগুলি প্রেরণ করেন (যেমন ফাইল আপলোড করা) এটির কারণ হতে পারে । এটি এড়াতে, আপনি এটি সেট করতে চান HttpURLConnection#setFixedLengthStreamingMode()
।
httpConnection.setFixedLengthStreamingMode(contentLength);
তবে যদি সামগ্রীর দৈর্ঘ্যটি সত্যই আগে জানা থাকে না তবে আপনি সেই HttpURLConnection#setChunkedStreamingMode()
অনুযায়ী সেট করে চুনযুক্ত স্ট্রিমিং মোডটি ব্যবহার করতে পারেন । এটি এইচটিটিপি 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
মিশ্র পোস্টের সামগ্রী (বাইনারি এবং চরিত্রের ডেটা) জন্য এনকোডিং ব্যবহার করবেন। এনকোডিংটি আরএফসি 2388-এ বর্ণিত আরও বিশদে রয়েছে ।
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, ইত্যাদি) চালু নেই। Servlet 3.0 এর আগে, আপনার সেরা পছন্দটি একটি অনুরোধ পার্স করতে অ্যাপাচি কমন্স ফাইলআপলোড ব্যবহার করছে p ফাইল-আপলোড এবং সার্ভেল্ট 3.0.০ পদ্ধতির উভয়ের উদাহরণের জন্য এই উত্তরটিmultipart/form-data
দেখুন ।
অবিশ্বস্ত বা ভুল কনফিগার করা এইচটিটিপিএস সাইটগুলির সাথে লেনদেন করা
কখনও কখনও আপনাকে এইচটিটিপিএস ইউআরএল সংযুক্ত করা দরকার, সম্ভবত আপনি ওয়েব স্ক্র্যাপ লিখেছেন। সেক্ষেত্রে আপনি সম্ভবত javax.net.ssl.SSLException: Not trusted server certificate
কিছু এইচটিটিপিএস সাইটগুলির মুখোমুখি হতে পারেন যারা তাদের এসএসএল শংসাপত্রগুলি আপ টু ডেট রাখে না, বা একটি java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found
বা javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name
কিছু ভুল কনফিগার করা এইচটিটিপিএস সাইটগুলিতে।
static
আপনার ওয়েব স্ক্র্যাপার ক্লাসে নিম্নলিখিত এক-সময় পরিচালিত ইনিশিয়ালাইজারটি HttpsURLConnection
সেই এইচটিটিপিএস সাইটগুলিকে আরও হালকা করা উচিত এবং এইভাবে ব্যতিক্রমগুলি আর ছুঁড়ে দেওয়া উচিত নয়।
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 হয় অনেক MORE জনকে এই সব সুবিধাজনক :)
পার্সিং এবং এইচটিএমএল উত্তোলন
আপনি যদি চান সমস্তই এইচটিএমএল থেকে ডেটা পার্সিং এবং নিষ্কাশন করছে তবে জসুপের মতো এইচটিএমএল পার্সার আরও ভাল ব্যবহার করুন