httprequest - كيفية استخدام java.net.URLConnection لاطلاق النار والتعامل مع طلبات HTTP




httpurlconnection (11)

يتم استخدام java.net.URLConnection حول هذا الموضوع كثيرًا هنا ، كما أن برنامج Oracle التعليمي موجز للغاية حول هذا الموضوع.

يوضح هذا البرنامج التعليمي أساسًا كيفية تنشيط طلب GET وقراءة الاستجابة. لا تشرح في أي مكان كيفية استخدامها من بين آخرين لتنفيذ طلب POST ، وتعيين رؤوس الطلبات ، وقراءة رؤوس الردود ، والتعامل مع ملفات تعريف الارتباط ، وإرسال نموذج HTML ، وتحميل ملف ، وما إلى ذلك.

لذا ، كيف يمكنني استخدام java.net.URLConnection لاطلاق النار والتعامل مع طلبات HTTP "المتقدمة"؟


Answers

هناك خياران يمكنك اتباعهما باستخدام HTTP URL Hits: GET / POST

الحصول على طلب: -

HttpURLConnection.setFollowRedirects(true); // defaults to true

String url = "https://name_of_the_url";
URL request_url = new URL(url);
HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection();
http_conn.setConnectTimeout(100000);
http_conn.setReadTimeout(100000);
http_conn.setInstanceFollowRedirects(true);
System.out.println(String.valueOf(http_conn.getResponseCode()));

طلب POST: -

HttpURLConnection.setFollowRedirects(true); // defaults to true

String url = "https://name_of_the_url"
URL request_url = new URL(url);
HttpURLConnection http_conn = (HttpURLConnection)request_url.openConnection();
http_conn.setConnectTimeout(100000);
http_conn.setReadTimeout(100000);
http_conn.setInstanceFollowRedirects(true);
http_conn.setDoOutput(true);
PrintWriter out = new PrintWriter(http_conn.getOutputStream());
if (urlparameter != null) {
   out.println(urlparameter);
}
out.close();
out = null;
System.out.println(String.valueOf(http_conn.getResponseCode()));

if you are using http get please remove this line

urlConnection.setDoOutput(true);

أولاً إخلاء المسؤولية مسبقًا: مقتطفات الشفرة المنشورة هي كل الأمثلة الأساسية. ستحتاج إلى التعامل مع IOException S و RuntimeException مثل NullPointerException ، ArrayIndexOutOfBoundsException نفسك.

خطة

نحتاج أولاً إلى معرفة عنوان URL و charset على الأقل. المعلمات اختيارية وتعتمد على المتطلبات الوظيفية.

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

يجب أن تكون معلمات الاستعلام بتنسيق name=value وتكون متصلاً بواسطة & . عادةً ما تقوم أيضًا URL-encode محددات طلب البحث مع المجموعة المحددة باستخدام 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() طريقة 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. معيار 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 برمجيًا ، لا تنس أن تأخذ أزواج name=value من أي عناصر <input type="hidden"> في سلسلة الاستعلام ، وبالطبع أيضًا name=value الزوج name=value <input type="submit"> العنصر الذي ترغب في "الضغط عليه" برمجيًا (لأنه عادةً ما يتم استخدامه في جانب الخادم للتمييز إذا تم الضغط على زر وإذا كان الأمر كذلك ، أيهما).

يمكنك أيضًا إرسال java.net.URLConnection تم الحصول عليه إلى HttpURLConnection واستخدام HttpURLConnection#setRequestMethod() بدلاً من ذلك. ولكن إذا كنت تحاول استخدام الاتصال للإخراج ، فستحتاج إلى تعيين URLConnection#setDoOutput() على true .

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

وفي كلتا الحالتين ، إذا كان الجانب الآخر عبارة عن HttpServlet ، فسيتم doPost() الخاصة به doPost() المعلمات من خلال HttpServletRequest#getParameter() .

في الواقع اطلاق طلب HTTP

يمكنك إطلاق طلب HTTP بشكل صريح باستخدام URLConnection#connect() ، ولكن سيتم إطلاق الطلب تلقائيًا عند الطلب عندما تريد الحصول على أي معلومات حول استجابة HTTP ، مثل نص الاستجابة باستخدام URLConnection#getInputStream() وما إلى ذلك. تقوم الأمثلة المذكورة أعلاه بهذا بالضبط ، لذلك فإن connect() هو في الواقع غير ضروري.

جمع معلومات استجابة HTTP

  1. حالة استجابة HTTP :

    أنت في حاجة إلى HttpURLConnection هنا. يلقي عليه أولا إذا لزم الأمر.

    int status = httpConnection.getResponseCode();
    
  2. رؤوس استجابة HTTP :

    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
    
  3. تشفير استجابة 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 cookie.substring(0, cookie.indexOf(';')) path وغير ذلك. بدلاً من ذلك ، يمكنك أيضًا استخدام cookie.substring(0, cookie.indexOf(';')) بدلا من split() .

وضع الجري

سيقوم HttpURLConnection بشكل افتراضي HttpURLConnection نص الطلب بالكامل قبل إرساله فعليًا ، بغض النظر عما إذا كنت قد قمت بتعيين طول محتوى ثابت بنفسك باستخدام connection.setRequestProperty("Content-Length", contentLength); . قد يتسبب هذا في OutOfMemoryException s عندما تقوم في نفس الوقت بإرسال طلبات POST كبيرة (مثل تحميل الملفات). لتجنب هذا ، ترغب في تعيين HttpURLConnection#setFixedLengthStreamingMode() .

httpConnection.setFixedLengthStreamingMode(contentLength);

ولكن إذا كان طول المحتوى غير معروف مسبقًا ، فيمكنك استخدام وضع البث المقسم عن طريق تعيين HttpURLConnection#setChunkedStreamingMode() وفقًا لذلك. سيؤدي هذا إلى تعيين رأس HTTP Transfer-Encoding chunked الذي سيؤدي إلى إرسال نص الطلب في أجزاء. المثال التالي سيرسل الجسم في أجزاء من 1 كيلوبايت.

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() جديدة نسبيًا ، تم تقديمها في Servlet 3.0 (Glassfish 3 ، Tomcat 7 ، إلخ). قبل Servlet 3.0 ، فإن أفضل خيار هو استخدام Apache Commons FileUpload لتحليل طلب multipart/form-data . انظر أيضًا هذه الإجابة للحصول على أمثلة لكل من FileUpload و طرق Servelt 3.0.

التعامل مع مواقع HTTPS غير موثوق بها أو تمت تهيئتها بشكل غير صحيح

في بعض الأحيان تحتاج إلى توصيل عنوان HTTPS ، ربما لأنك تكتب مكشطة ويب. في هذه الحالة ، من المحتمل أن تواجه 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 التي تمت javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name .

HttpsURLConnection 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 ، فمن الأفضل استخدام محلل HTML مثل Jsoup


عند العمل باستخدام HTTP ، يكون من المفيد دائمًا الرجوع إلى HttpURLConnection بدلاً من الفئة الأساسية URLConnection (حيث إن URLConnection هو فئة تجريدية عندما تطلب URLConnection.openConnection() على عنوان URL الخاص بـ HTTP وهو ما ستعود إليه على أي حال).

ثم يمكنك بدلاً من الاعتماد على URLConnection#setDoOutput(true) لتعيين طريقة الطلب ضمنيًا على POST بدلاً من ذلك القيام httpURLConnection.setRequestMethod("POST") والتي قد يجدها البعض أكثر طبيعية (والتي تسمح لك أيضًا بتحديد طرق الطلب الأخرى مثل PUT ، DELETE ، ...).

كما يوفر ثوابت HTTP مفيدة حتى تتمكن من القيام بما يلي:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

مستوحاة من هذا وأسئلة أخرى حول SO ، لقد قمت بإنشاء الحد الأدنى 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

هدفي هو توفير الأشياء المشتركة التي قد يرغب المرء في القيام بها بطريقة أسهل قليلاً ...


تحديث

يتم شحن عميل HTTP الجديد مع Java 9 ولكن كجزء من وحدة Incubator المسماة jdk.incubator.httpclient . وحدات الحاضنة هي وسيلة لوضع واجهات برمجة التطبيقات غير النهائية في أيدي المطورين بينما تقدم واجهات برمجة التطبيقات نحو وضع اللمسات الأخيرة أو الإزالة في إصدار مستقبلي.

في Java 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;
}

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&param2=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.


في البداية تم تضليلي من خلال هذه article التي تفضل HttpClient .

في وقت لاحق لقد أدركت أن HttpURLConnection سيبقى من هذه article

وفقًا لمدونة Google :

يحتوي عميل Apache HTTP على أخطاء أقل في Eclair و Froyo. هذا هو الخيار الأفضل لهذه الإصدارات. بالنسبة لـ Gingerbread ، فإن HttpURLConnection هو الخيار الأفضل. واجهة برمجة التطبيقات البسيطة والصغيرة الحجم تجعلها مناسبة تمامًا للأندرويد.

يعمل الضغط الشفاف والتخزين المؤقت للاستجابة على تقليل استخدام الشبكة وتحسين السرعة وتوفير البطارية. يجب أن تستخدم التطبيقات الجديدة HttpURLConnection؛ هذا هو المكان الذي سنمضي فيه طاقاتنا للمضي قدمًا.

بعد قراءة rapidvaluesolutions.com/tech_blog/… وبعض الأسئلة الأخرى حول تدفق الأسئلة ، أنا مقتنع بأن HttpURLConnection سيبقى لفترات أطول.

بعض أسئلة SE HttpURLConnections لصالح HttpURLConnections :

على نظام التشغيل Android ، يمكنك تقديم طلب POST باستخدام بيانات نموذج URL المشفر بدون استخدام UrlEncodedFormEntity

يعمل HttpPost في مشروع جافا ، وليس في Android


أقترح عليك إلقاء نظرة على الكود الموجود على kevinsawicki/http-request ، وهو عبارة عن غلاف في الجزء العلوي من HttpUrlConnection يوفر واجهة برمجة تطبيقات أبسط بكثير إذا كنت تريد فقط تقديم الطلبات في الوقت الحالي أو يمكنك إلقاء نظرة على المصادر (ليس كبيرًا جدًا) لإلقاء نظرة على كيفية التعامل مع الاتصالات.

مثال: تقديم طلب GET مع application/json نوع المحتوى application/json وبعض معلمات طلب البحث:

// GET http://google.com?q=baseball%20gloves&size=100
String response = HttpRequest.get("http://google.com", true, "q", "baseball gloves", "size", 100)
        .accept("application/json")
        .body();
System.out.println("Response was: " + response);

يتم تعريف سجل اسم حقل رأس في RFC3864 ولا يوجد شيء خاص بـ "X-".

بقدر ما أستطيع أن أقول ، لا توجد مبادئ توجيهية للرؤوس الخاصة ؛ في شك ، تجنبها. أو إلقاء نظرة على إطار عمل امتداد HTTP ( RFC 2774 ).

سيكون من المثير للاهتمام فهم المزيد من حالة الاستخدام ؛ لماذا لا يمكن إضافة المعلومات إلى نص الرسالة؟





java http httprequest httpurlconnection urlconnection