Câu hỏi Cách sử dụng java.net.URLConnection để kích hoạt và xử lý các yêu cầu HTTP


Sử dụng java.net.URLConnection được hỏi về khá thường xuyên ở đây và Hướng dẫn của Oracle Là quá súc tích về nó.

Hướng dẫn đó về cơ bản chỉ cho thấy cách kích hoạt yêu cầu GET và đọc phản hồi. Nó không giải thích bất cứ nơi nào cách sử dụng nó cho những người khác thực hiện yêu cầu POST, đặt tiêu đề yêu cầu, đọc tiêu đề phản hồi, xử lý cookie, gửi biểu mẫu HTML, tải lên tệp, v.v.

Vì vậy, làm thế nào tôi có thể sử dụng java.net.URLConnection thế nào để kích hoạt và xử lý các yêu cầu HTTP "nâng cao"?


1762


gốc




Các câu trả lời:


Trước tiên, tuyên bố từ chối trách nhiệm: các đoạn mã được đăng là tất cả các ví dụ cơ bản. Bạn sẽ cần phải xử lý tầm thường IOExceptioncát RuntimeExceptiongiống như NullPointerException, ArrayIndexOutOfBoundsException và tự kết hợp.


Đang chuẩn bị

Đầu tiên chúng ta cần biết ít nhất URL và bộ ký tự. Các tham số là tùy chọn và phụ thuộc vào các yêu cầu chức năng.

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));

Tham số truy vấn phải nằm trong name=value định dạng và được nối bởi &. Bạn cũng bình thường Mã hóa URL các tham số truy vấn với bộ ký tự được chỉ định sử dụng URLEncoder#encode().

Các String#format() chỉ để thuận tiện. Tôi thích nó khi tôi cần toán tử nối chuỗi + hơn hai lần.


Bắn một HTTP GET yêu cầu với các tham số truy vấn (tùy chọn)

Đó là một nhiệm vụ tầm thường. Đó là phương thức yêu cầu mặc định.

URLConnection connection = new URL(url + "?" + query).openConnection();
connection.setRequestProperty("Accept-Charset", charset);
InputStream response = connection.getInputStream();
// ...

Bất kỳ chuỗi truy vấn nào sẽ được nối với URL bằng cách sử dụng ?. Các Accept-Charset tiêu đề có thể gợi ý máy chủ những gì mã hóa các tham số. Nếu bạn không gửi bất kỳ chuỗi truy vấn nào, thì bạn có thể rời khỏi Accept-Charset tiêu đề đi. Nếu bạn không cần đặt bất kỳ tiêu đề nào, bạn thậm chí có thể sử dụng URL#openStream() phương pháp tắt.

InputStream response = new URL(url).openStream();
// ...

Dù bằng cách nào, nếu phía bên kia là HttpServlet, sau đó nó là doGet() phương thức sẽ được gọi và các thông số sẽ có sẵn bằng HttpServletRequest#getParameter().

Đối với mục đích thử nghiệm, bạn có thể in nội dung phản hồi thành stdout như dưới đây:

try (Scanner scanner = new Scanner(response)) {
    String responseBody = scanner.useDelimiter("\\A").next();
    System.out.println(responseBody);
}

Bắn một HTTP POST yêu cầu với tham số truy vấn

Đặt URLConnection#setDoOutput() đến true ngầm đặt phương thức yêu cầu thành POST. HTTP POST chuẩn dưới dạng biểu mẫu web có dạng application/x-www-form-urlencoded trong đó chuỗi truy vấn được ghi vào phần thân yêu cầu.

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();
// ...

Lưu ý: bất cứ khi nào bạn muốn gửi biểu mẫu HTML theo lập trình, đừng quên lấy name=value cặp của bất kỳ <input type="hidden"> các thành phần vào chuỗi truy vấn và dĩ nhiên cũng là name=value cặp của <input type="submit"> phần tử mà bạn muốn "nhấn" theo lập trình (vì nó thường được sử dụng ở phía máy chủ để phân biệt nếu một nút được nhấn và nếu có, cái nào đã được nhấn).

Bạn cũng có thể truyền URLConnection đến HttpURLConnection và sử dụng HttpURLConnection#setRequestMethod() thay thế. Nhưng nếu bạn đang cố gắng sử dụng kết nối cho đầu ra bạn vẫn cần phải thiết lập URLConnection#setDoOutput() đến true.

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

Dù bằng cách nào, nếu phía bên kia là HttpServlet, sau đó nó là doPost() phương thức sẽ được gọi và các thông số sẽ có sẵn bằng HttpServletRequest#getParameter().


Thực sự kích hoạt yêu cầu HTTP

Bạn có thể kích hoạt yêu cầu HTTP một cách rõ ràng URLConnection#connect()nhưng yêu cầu sẽ tự động được kích hoạt theo yêu cầu khi bạn muốn nhận bất kỳ thông tin nào về phản hồi HTTP, chẳng hạn như nội dung phản hồi bằng URLConnection#getInputStream()và vân vân. Các ví dụ trên thực hiện chính xác điều đó, vì vậy connect() gọi là trong thực tế thừa.


Thu thập thông tin phản hồi HTTP

  1. Trạng thái phản hồi HTTP:

    Bạn cần một HttpURLConnection đây. Hãy đúc nó trước nếu cần.

    int status = httpConnection.getResponseCode();
    
  2. Tiêu đề phản hồi HTTP:

    for (Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
        System.out.println(header.getKey() + "=" + header.getValue());
    }
    
  3. Mã hóa phản hồi HTTP:

    Khi mà Content-Type chứa một charset thông số, sau đó cơ thể phản hồi có khả năng dựa trên văn bản và chúng tôi muốn xử lý phần thân phản hồi bằng mã hóa ký tự được chỉ định phía máy chủ.

    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.
    }
    

Duy trì phiên

Phiên phía máy chủ thường được hỗ trợ bởi cookie. Một số biểu mẫu web yêu cầu bạn đã đăng nhập và / hoặc được theo dõi bởi một phiên. Bạn có thể dùng CookieHandler API để duy trì cookie. Bạn cần chuẩn bị một CookieManager với một CookiePolicy của ACCEPT_ALL trước khi gửi tất cả các yêu cầu 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();
// ...

Lưu ý rằng điều này được biết là không phải lúc nào cũng hoạt động bình thường trong mọi trường hợp. Nếu nó không thành công cho bạn, thì tốt nhất là thu thập thủ công và đặt tiêu đề cookie. Về cơ bản bạn cần lấy tất cả Set-Cookie tiêu đề từ phản hồi của thông tin đăng nhập hoặc lần đầu tiên GET yêu cầu và sau đó vượt qua điều này thông qua các yêu cầu tiếp theo.

// 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]);
}
// ...

Các split(";", 2)[0] là để loại bỏ các thuộc tính cookie không liên quan đến phía máy chủ như expires, path, v.v. Ngoài ra, bạn cũng có thể sử dụng cookie.substring(0, cookie.indexOf(';')) thay vì split().


Chế độ phát trực tuyến

Các HttpURLConnection sẽ theo mặc định đệm toàn thể yêu cầu nội dung trước khi thực sự gửi nó, bất kể bạn đã tự đặt độ dài nội dung cố định hay chưa connection.setRequestProperty("Content-Length", contentLength);. Điều này có thể gây ra OutOfMemoryExceptions bất cứ khi nào bạn đồng thời gửi các yêu cầu POST lớn (ví dụ: tải tệp lên). Để tránh điều này, bạn muốn đặt HttpURLConnection#setFixedLengthStreamingMode().

httpConnection.setFixedLengthStreamingMode(contentLength);

Nhưng nếu độ dài nội dung thực sự không được biết trước, thì bạn có thể sử dụng chế độ phát trực tuyến bằng cách đặt HttpURLConnection#setChunkedStreamingMode() cho phù hợp. Điều này sẽ thiết lập HTTP Transfer-Encoding tiêu đề đến chunked sẽ buộc cơ thể yêu cầu được gửi theo khối. Ví dụ bên dưới sẽ gửi nội dung theo khối 1KB.

httpConnection.setChunkedStreamingMode(1024);

Đại lý người dùng

Nó có thể xảy ra một yêu cầu trả về phản hồi không mong muốn, trong khi nó hoạt động tốt với trình duyệt web thực. Phía máy chủ có thể chặn các yêu cầu dựa trên User-Agent tiêu đề yêu cầu. Các URLConnection theo mặc định sẽ đặt nó thành Java/1.6.0_19 nơi phần cuối cùng rõ ràng là phiên bản JRE. Bạn có thể ghi đè điều này như sau:

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.

Sử dụng chuỗi User-Agent từ một trình duyệt gần đây.


Xử lý lỗi

Nếu mã phản hồi HTTP là 4nn (Lỗi ứng dụng khách) hoặc 5nn (Lỗi máy chủ), sau đó bạn có thể muốn đọc HttpURLConnection#getErrorStream() để xem liệu máy chủ có gửi bất kỳ thông tin lỗi hữu ích nào không.

InputStream error = ((HttpURLConnection) connection).getErrorStream();

Nếu mã phản hồi HTTP là -1, thì có sự cố với kết nối và xử lý phản hồi. Các HttpURLConnection việc triển khai thực hiện trong các JRE cũ hơn phần nào có lỗi với việc giữ các kết nối còn sống. Bạn có thể muốn tắt nó đi bằng cách thiết lập http.keepAlive thuộc tính hệ thống false. Bạn có thể làm điều này theo chương trình trong phần đầu của ứng dụng của bạn bằng cách:

System.setProperty("http.keepAlive", "false");

Tải tệp lên

Bạn thường sử dụng multipart/form-data mã hóa cho nội dung POST hỗn hợp (dữ liệu nhị phân và ký tự). Mã hóa được mô tả chi tiết hơn trong 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();
}

Nếu phía bên kia là một HttpServlet, sau đó nó là doPost() phương pháp sẽ được gọi và các bộ phận sẽ có sẵn bởi HttpServletRequest#getPart() (lưu ý, do đó không phải  getParameter() và cứ thế!). Các getPart() Tuy nhiên, phương pháp này tương đối mới, được giới thiệu trong Servlet 3.0 (Glassfish 3, Tomcat 7, v.v.). Trước Servlet 3.0, lựa chọn tốt nhất của bạn là sử dụng Apache Commons FileUpload phân tích cú pháp multipart/form-data yêu cầu. Cũng thấy câu trả lời này cho các ví dụ về cả phương pháp FileUpload và Servelt 3.0.


Xử lý các trang web HTTPS không được tin cậy hoặc bị định cấu hình sai

Đôi khi bạn cần kết nối URL HTTPS, có lẽ vì bạn đang viết một trình duyệt web. Trong trường hợp đó, bạn có thể phải đối mặt với javax.net.ssl.SSLException: Not trusted server certificate trên một số trang web HTTPS không cập nhật chứng chỉ SSL của họ hoặc java.security.cert.CertificateException: No subject alternative DNS name matching [hostname] found hoặc là javax.net.ssl.SSLProtocolException: handshake alert: unrecognized_name trên một số trang web HTTPS được định cấu hình sai.

Sau một lần chạy static initializer trong lớp scraper web của bạn nên làm cho HttpsURLConnection khoan dung hơn với các trang HTTPS đó và do đó không ném những ngoại lệ đó nữa.

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);
    }
}

Những từ cuối

Các Apache HttpComponents HttpClient Là nhiều thuận tiện hơn trong tất cả điều này :)


Phân tích cú pháp và trích xuất HTML

Nếu tất cả những gì bạn muốn là phân tích cú pháp và trích xuất dữ liệu từ HTML, thì tốt hơn hãy sử dụng trình phân tích cú pháp HTML như Jsoup


2526



Trước tiên, bạn nên đặt liên kết apache, vì vậy mọi người tìm kiếm giải pháp sẽ tìm thấy nó nhanh hơn;) - ZeissS
@ivanceras: Nếu bạn không thể đun sôi nó dựa trên thông tin trong câu trả lời này, thì hãy nhấn Ask Question nút ở phía trên bên phải. - BalusC
@Brais: Vui lòng đọc thông số kỹ thuật. Các -- một phần không phải là một phần của chính ranh giới đó. Nó chỉ là một chuỗi phân cách. Tôi đã khôi phục bản chỉnh sửa không hợp lệ của bạn. - BalusC
@BalusC cảm ơn rất nhiều cho một hướng dẫn hoàn hảo như vậy. Cũng vui lòng bao gồm tiêu đề như "Đóng luồng / kết nối". Tôi thực sự bối rối về thời gian và luồng / kết nối nào đóng.
Phần buồn là trên Android nó là không phải đề nghị sử dụng Apache HttpClient bây giờ và HttpURLConnection là tàn nhẫn. android-developers.blogspot.in/2011/09/… - yati sagade


Khi làm việc với HTTP, hầu như luôn hữu ích hơn khi tham khảo HttpURLConnection thay vì lớp cơ sở URLConnection (kể từ URLConnection là một lớp trừu tượng khi bạn yêu cầu URLConnection.openConnection() trên một URL HTTP là những gì bạn sẽ nhận được trở lại anyway).

Sau đó, bạn có thể thay vì dựa vào URLConnection#setDoOutput(true) để ngầm thiết lập phương thức yêu cầu BÀI ĐĂNG thay vào đó httpURLConnection.setRequestMethod("POST") mà một số có thể tìm thấy tự nhiên hơn (và cũng cho phép bạn chỉ định các phương thức yêu cầu khác như ĐẶT, XÓA BỎ, ...).

Nó cũng cung cấp các hằng số HTTP hữu ích để bạn có thể thực hiện:

int responseCode = httpURLConnection.getResponseCode();

if (responseCode == HttpURLConnection.HTTP_OK) {

84



setDoOutPut đúng là vấn đề của tôi mà đặt GET của tôi thành POST. Cảm ơn - Patrick Kafka
Nếu bạn đang cố ghi dữ liệu vào outputstream phải vẫn thiết lập setDoOutput() đến true nếu không thì ngoại lệ sẽ bị ném (ngay cả khi bạn setRequestMethod("POST")). Để được rõ ràng: thiết lập URLConnection#setDoOutput(true) đến true ngầm đặt phương thức yêu cầu thành POST, nhưng thiết lập httpURLConnection.setRequestMethod("POST") tới POST không phải đặt ngầm setDoOutput() đến true. - Tony Chan


Lấy cảm hứng từ câu hỏi này và các câu hỏi khác về SO, tôi đã tạo một nguồn mở tối thiểu basic-http-client thể hiện hầu hết các kỹ thuật được tìm thấy ở đây.

google-http-java-client cũng là một nguồn tài nguyên mã nguồn mở tuyệt vời.


49



Tôi chỉ nghĩ như vậy. Nhưng cũng có thể có một thư viện Java đơn giản / đơn giản chỉ sử dụng mã URLConnection như được trình bày ở đây để đóng gói mã cho các phương thức đơn giản hơn để thực hiện HTTP GET, POST, vv Thư viện sau đó có thể được biên dịch và đóng gói như JAR và được nhập / sử dụng trong mã Java hoặc tệp lớp nguồn có thể được bao gồm trong dự án Java nếu các JAR bên ngoài không được mong muốn. Điều này có thể được thực hiện với các thư viện khác như Apache, v.v. nhưng có nhiều đau hơn so với một thư viện lớp tập tin đơn giản sử dụng URLConnection. - David
rapidvaluesolutions.com/tech_blog/… ủng hộ HttpURLConnection trên HttpClient - Ravindra babu


Có 2 tùy chọn bạn có thể truy cập với Số lần truy cập URL HTTP: GET / POST

Yêu cầu GET: -

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()));

Yêu cầu 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()));

22



Có khá nhiều hơn nữa: PUT, DELETE, HEAD, ... - user207421
Bạn có thể xem phản hồi JSON thực tế như thế nào? - Surenzxx


Tôi đề nghị bạn hãy xem mã trên kevinsawicki / http-request, về cơ bản nó là một trình bao bọc trên đầu HttpUrlConnection nó cung cấp một API đơn giản hơn nhiều trong trường hợp bạn chỉ muốn thực hiện các yêu cầu ngay bây giờ hoặc bạn có thể xem các nguồn (nó không quá lớn) để xem các kết nối được xử lý như thế nào.

Ví dụ: Tạo một GET yêu cầu với loại nội dung application/json và một số tham số truy vấn:

// 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);

20





Tôi cũng rất lấy cảm hứng từ câu trả lời này.

Tôi thường vào các dự án mà tôi cần phải thực hiện một số HTTP và tôi có thể không muốn mang lại nhiều phụ thuộc bên thứ 3 (mang lại những người khác và v.v ...)

Tôi bắt đầu viết các tiện ích của riêng mình dựa trên một số cuộc hội thoại này (không phải bất kỳ nơi nào đã thực hiện):

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 {

Sau đó, chỉ có một bó hoặc phương pháp tĩnh.

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;
    }
}

Sau đó đăng ...

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;
}

Chà, bạn hiểu ý rồi đó....

Dưới đây là các bài kiểm tra:

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);


}

Bạn có thể tìm phần còn lại ở đây:

https://github.com/RichardHightower/boon

Mục tiêu của tôi là cung cấp những thứ thông thường mà người ta muốn làm theo cách dễ dàng hơn một chút sau đó ....


19



Đó là kỳ quặc rằng trong doPost phương pháp có một charset param, được sử dụng để đặt tiêu đề yêu cầu, nhưng sau đó dữ liệu được viết bằng một số bộ mã được mã hóa cứng IO.CHARSET. Một lỗi? - Vit Khudenko


Cập nhật

Ứng dụng khách HTTP mới được vận chuyển với Java 9 nhưng là một phần của   Mô-đun lồng ấp có tên jdk.incubator.httpclient. Các mô-đun lồng ấp là   một phương tiện đưa các API không phải là cuối cùng vào tay các nhà phát triển trong khi   API tiến triển theo hướng hoàn thiện hoặc xóa trong tương lai   giải phóng.

Trong Java 9, bạn có thể gửi GET yêu cầu như:

// GET
HttpResponse response = HttpRequest
    .create(new URI("http://www.stackoverflow.com"))
    .headers("Foo", "foovalue", "Bar", "barvalue")
    .GET()
    .response();

Sau đó, bạn có thể kiểm tra trả lại HttpResponse:

int statusCode = response.statusCode();
String responseBody = response.body(HttpResponse.asString());

Vì ứng dụng HTTP mới này nằm trong java.httpclient  jdk.incubator.httpclient mô-đun, bạn nên khai báo sự phụ thuộc này trong module-info.java tập tin:

module com.foo.bar {
    requires jdk.incubator.httpclient;
}

15





Ban đầu tôi đã bị lừa bởi điều này bài báo ủng hộ HttpClient.

Sau đó tôi đã nhận ra rằng HttpURLConnection sẽ ở lại đây bài báo

Theo blog của Google:

Máy khách Apache HTTP có ít lỗi hơn trên Eclair và Froyo. Đây là lựa chọn tốt nhất cho các bản phát hành này. Đối với Gingerbread, HttpURLConnection là lựa chọn tốt nhất. API đơn giản và kích thước nhỏ của nó làm cho nó phù hợp với Android.

Nén trong suốt và bộ nhớ đệm phản hồi giảm sử dụng mạng, cải thiện tốc độ và tiết kiệm pin. Các ứng dụng mới nên sử dụng HttpURLConnection; đó là nơi chúng ta sẽ tiêu tốn năng lượng của mình trong tương lai.

Sau khi đọc bài viết này và một số câu hỏi khác trên luồng, tôi tin rằng HttpURLConnection sẽ ở lại lâu hơn.

Một số câu hỏi SE ưa thích HttpURLConnections:

Trên Android, thực hiện yêu cầu POST với dữ liệu Biểu mẫu mã hóa URL mà không sử dụng UrlEncodedFormEntity

HttpPost hoạt động trong dự án Java, không có trong Android


14





Bạn cũng có thể dùng JdkRequest từ jcabi-http (Tôi là nhà phát triển), tất cả điều này đều phù hợp với bạn, trang trí HttpURLConnection, kích hoạt các yêu cầu HTTP và phân tích cú pháp phản hồi, ví dụ:

String html = new JdkRequest("http://www.google.com").fetch().body();

Kiểm tra bài đăng trên blog này để biết thêm thông tin: http://www.yegor256.com/2014/04/11/jcabi-http-intro.html


11



Làm cách nào để bạn xử lý cookie? - Dejell


Cũng có OkHttp, là một ứng dụng HTTP có hiệu quả theo mặc định:

  • Hỗ trợ HTTP / 2 cho phép tất cả các yêu cầu tới cùng một máy chủ để chia sẻ một socket.
  • Kết nối tổng hợp giảm độ trễ yêu cầu (nếu HTTP / 2 không khả dụng).
  • GZIP trong suốt thu nhỏ kích thước tải xuống.
  • Bộ nhớ đệm phản hồi tránh hoàn toàn mạng cho các yêu cầu lặp lại.

Đầu tiên tạo một thể hiện của OkHttpClient:

OkHttpClient client = new OkHttpClient();

Sau đó, chuẩn bị GET yêu cầu:

Request request = new Request.Builder()
      .url(url)
      .build();

cuối cùng, sử dụng OkHttpClient gửi chuẩn bị Request:

Response response = client.newCall(request).execute();

Để biết thêm chi tiết, bạn có thể tham khảo Tài liệu của OkHttp


11





nếu bạn đang sử dụng http get xin vui lòng loại bỏ dòng này

urlConnection.setDoOutput(true);

10