Gửi yêu cầu POST HTTP trong Java


294

hãy giả sử URL này ...

http://www.example.com/page.php?id=10            

(Ở đây id cần được gửi trong yêu cầu POST)

Tôi muốn gửi id = 10đến máy chủ page.php, chấp nhận nó theo phương thức POST.

Làm thế nào tôi có thể làm điều này từ trong Java?

Tôi đã thử điều này:

URL aaa = new URL("http://www.example.com/page.php");
URLConnection ccc = aaa.openConnection();

Nhưng tôi vẫn không thể tìm ra cách gửi nó qua POST

Câu trả lời:


339

Cập nhật câu trả lời:

Do một số lớp, trong câu trả lời ban đầu, không được dùng trong phiên bản mới hơn của các Thành phần HTTP Apache, nên tôi sẽ đăng bản cập nhật này.

Nhân tiện, bạn có thể truy cập tài liệu đầy đủ để biết thêm ví dụ ở đây .

HttpClient httpclient = HttpClients.createDefault();
HttpPost httppost = new HttpPost("http://www.a-domain.com/foo/");

// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>(2);
params.add(new BasicNameValuePair("param-1", "12345"));
params.add(new BasicNameValuePair("param-2", "Hello!"));
httppost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));

//Execute and get the response.
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();

if (entity != null) {
    try (InputStream instream = entity.getContent()) {
        // do something useful
    }
}

Câu trả lời gốc:

Tôi khuyên bạn nên sử dụng Apache httpClient. nó nhanh hơn và dễ thực hiện hơn.

HttpPost post = new HttpPost("http://jakarata.apache.org/");
NameValuePair[] data = {
    new NameValuePair("user", "joe"),
    new NameValuePair("password", "bloggs")
};
post.setRequestBody(data);
// execute method and handle any error responses.
...
InputStream in = post.getResponseBodyAsStream();
// handle response.

để biết thêm thông tin, hãy kiểm tra url này: http://hc.apache.org/


25
Sau khi thử một lúc để có được bàn tay của tôi PostMethod, dường như nó thực sự được gọi HttpPostlà theo stackoverflow.com/a/9242394/1338936 - chỉ dành cho bất cứ ai tìm thấy câu trả lời này như tôi đã làm :)
Martin Lyne

1
@Juan (và Martin Lyne) cảm ơn bạn đã cho ý kiến. Tôi vừa cập nhật câu trả lời.
mhshams

Câu trả lời sửa đổi của bạn vẫn sử dụng hc.apache.org?
djangofan

@djangofan vâng. có một liên kết đến apache-hc trong câu trả lời sửa đổi quá.
mhshams

6
bạn nên thêm libs đã nhập
gouchaoer

191

Gửi một yêu cầu POST rất dễ dàng trong vanilla Java. Bắt đầu với a URL, chúng ta cần chuyển đổi nó sang URLConnectionsử dụng url.openConnection();. Sau đó, chúng ta cần truyền nó tới a HttpURLConnection, vì vậy chúng ta có thể truy cập setRequestMethod()phương thức của nó để đặt phương thức của chúng ta. Cuối cùng chúng tôi nói rằng chúng tôi sẽ gửi dữ liệu qua kết nối.

URL url = new URL("https://www.example.com/login");
URLConnection con = url.openConnection();
HttpURLConnection http = (HttpURLConnection)con;
http.setRequestMethod("POST"); // PUT is another valid option
http.setDoOutput(true);

Sau đó chúng ta cần nói rõ những gì chúng ta sẽ gửi:

Gửi một hình thức đơn giản

Một POST bình thường đến từ một mẫu http có định dạng được xác định rõ . Chúng tôi cần chuyển đổi đầu vào của chúng tôi sang định dạng này:

Map<String,String> arguments = new HashMap<>();
arguments.put("username", "root");
arguments.put("password", "sjh76HSn!"); // This is a fake password obviously
StringJoiner sj = new StringJoiner("&");
for(Map.Entry<String,String> entry : arguments.entrySet())
    sj.add(URLEncoder.encode(entry.getKey(), "UTF-8") + "=" 
         + URLEncoder.encode(entry.getValue(), "UTF-8"));
byte[] out = sj.toString().getBytes(StandardCharsets.UTF_8);
int length = out.length;

Sau đó chúng tôi có thể đính kèm nội dung biểu mẫu của chúng tôi vào yêu cầu http với các tiêu đề thích hợp và gửi nó.

http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
    os.write(out);
}
// Do something with http.getInputStream()

Gửi JSON

Chúng tôi cũng có thể gửi json bằng java, điều này cũng dễ dàng:

byte[] out = "{\"username\":\"root\",\"password\":\"password\"}" .getBytes(StandardCharsets.UTF_8);
int length = out.length;

http.setFixedLengthStreamingMode(length);
http.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
http.connect();
try(OutputStream os = http.getOutputStream()) {
    os.write(out);
}
// Do something with http.getInputStream()

Hãy nhớ rằng các máy chủ khác nhau chấp nhận các loại nội dung khác nhau cho json, xem câu hỏi này .


Gửi tệp với bài viết java

Gửi tệp có thể được coi là khó khăn hơn để xử lý vì định dạng phức tạp hơn. Chúng tôi cũng sẽ thêm hỗ trợ để gửi các tệp dưới dạng chuỗi, vì chúng tôi không muốn đệm toàn bộ tệp vào bộ nhớ.

Đối với điều này, chúng tôi định nghĩa một số phương thức trợ giúp:

private void sendFile(OutputStream out, String name, InputStream in, String fileName) {
    String o = "Content-Disposition: form-data; name=\"" + URLEncoder.encode(name,"UTF-8") 
             + "\"; filename=\"" + URLEncoder.encode(filename,"UTF-8") + "\"\r\n\r\n";
    out.write(o.getBytes(StandardCharsets.UTF_8));
    byte[] buffer = new byte[2048];
    for (int n = 0; n >= 0; n = in.read(buffer))
        out.write(buffer, 0, n);
    out.write("\r\n".getBytes(StandardCharsets.UTF_8));
}

private void sendField(OutputStream out, String name, String field) {
    String o = "Content-Disposition: form-data; name=\"" 
             + URLEncoder.encode(name,"UTF-8") + "\"\r\n\r\n";
    out.write(o.getBytes(StandardCharsets.UTF_8));
    out.write(URLEncoder.encode(field,"UTF-8").getBytes(StandardCharsets.UTF_8));
    out.write("\r\n".getBytes(StandardCharsets.UTF_8));
}

Sau đó chúng ta có thể sử dụng các phương thức này để tạo một yêu cầu bài đăng nhiều phần như sau:

String boundary = UUID.randomUUID().toString();
byte[] boundaryBytes = 
           ("--" + boundary + "\r\n").getBytes(StandardCharsets.UTF_8);
byte[] finishBoundaryBytes = 
           ("--" + boundary + "--").getBytes(StandardCharsets.UTF_8);
http.setRequestProperty("Content-Type", 
           "multipart/form-data; charset=UTF-8; boundary=" + boundary);

// Enable streaming mode with default settings
http.setChunkedStreamingMode(0); 

// Send our fields:
try(OutputStream out = http.getOutputStream()) {
    // Send our header (thx Algoman)
    out.write(boundaryBytes);

    // Send our first field
    sendField(out, "username", "root");

    // Send a seperator
    out.write(boundaryBytes);

    // Send our second field
    sendField(out, "password", "toor");

    // Send another seperator
    out.write(boundaryBytes);

    // Send our file
    try(InputStream file = new FileInputStream("test.txt")) {
        sendFile(out, "identification", file, "text.txt");
    }

    // Finish the request
    out.write(finishBoundaryBytes);
}


// Do something with http.getInputStream()

5
Bài này rất hữu ích, nhưng khá thiếu sót. Phải mất 2 ngày để nó hoạt động. Vì vậy, để nó hoạt động, bạn phải thay thế StandartCharsets.UTF8 bằng StandardCharsets.UTF_8. ranh giớiBytes và finishBoundaryBytes cần nhận được hai dấu gạch nối bổ sung KHÔNG được truyền trong Kiểu nội dung, vì vậy ranh giớiBytes = ("-" + ranh giới + "\ r \ n"). TRƯỚC trường đầu tiên hoặc trường đầu tiên sẽ bị bỏ qua!
Algoman 22/03/2016

Tại sao out.write(finishBoundaryBytes);cần dòng? http.connect();sẽ thực hiện gửi POST, phải không?
János

16
Gửi một yêu cầu POST dễ dàng trong vanilla Java. Và sau đó, hàng chục dòng mã theo sau, so với một số thứ như requests.post('http://httpbin.org/post', data = {'key':'value'})trong Python, tôi mới biết về Java nên đây là một cách sử dụng rất lạ của từ "easy easy" đối với tôi :)
Lynn

1
Nó tương đối dễ dàng hơn những gì tôi mong đợi khi xem xét nó là Java :)
shaahiin

enigmatic \ r \ n \ r \ n có nghĩa là CRLF CRLF (vận chuyển trở lại + nguồn cấp dữ liệu). Nó tạo ra dòng mới gấp 2 lần. Dòng mới đầu tiên là kết thúc dòng hiện tại. Dòng thứ hai là để phân biệt tiêu đề http với cơ thể http trong một yêu cầu. HTTP là giao thức dựa trên ASCII. Đây là quy tắc để chèn \ r \ n.
Mitja Gustin

99
String rawData = "id=10";
String type = "application/x-www-form-urlencoded";
String encodedData = URLEncoder.encode( rawData, "UTF-8" ); 
URL u = new URL("http://www.example.com/page.php");
HttpURLConnection conn = (HttpURLConnection) u.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty( "Content-Type", type );
conn.setRequestProperty( "Content-Length", String.valueOf(encodedData.length()));
OutputStream os = conn.getOutputStream();
os.write(encodedData.getBytes());

Điều quan trọng cần lưu ý: sử dụng bất cứ thứ gì khác thì String.getBytes () dường như không hoạt động. Ví dụ, sử dụng PrintWriter hoàn toàn thất bại.
Bàn Bobby nhỏ

5
và làm thế nào để thiết lập 2 dữ liệu bài? Phân tách bằng dấu hai chấm, dấu phẩy?
con mèo ồn ào

10
encode(String)bị phản đối Bạn phải sử dụng encode(String, String), trong đó chỉ định loại mã hóa. Ví dụ : encode(rawData, "UTF-8").
sudo

3
Bạn có thể muốn theo dõi ở cuối. Điều này sẽ đảm bảo yêu cầu kết thúc và máy chủ có cơ hội xử lý phản hồi: Conn.getResponseCode ();
Szymon Jachim

3
không mã hóa toàn bộ chuỗi .. bạn phải mã hóa giá trị của từng tham số
user2914191

22

Câu trả lời đầu tiên rất hay, nhưng tôi phải thêm try / Catch để tránh lỗi trình biên dịch Java.
Ngoài ra, tôi gặp khó khăn khi tìm cách đọc các HttpResponsethư viện Java.

Đây là mã hoàn chỉnh hơn:

/*
 * Create the POST request
 */
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://example.com/");
// Request parameters and other properties.
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("user", "Bob"));
try {
    httpPost.setEntity(new UrlEncodedFormEntity(params, "UTF-8"));
} catch (UnsupportedEncodingException e) {
    // writing error to Log
    e.printStackTrace();
}
/*
 * Execute the HTTP Request
 */
try {
    HttpResponse response = httpClient.execute(httpPost);
    HttpEntity respEntity = response.getEntity();

    if (respEntity != null) {
        // EntityUtils to get the response content
        String content =  EntityUtils.toString(respEntity);
    }
} catch (ClientProtocolException e) {
    // writing exception to log
    e.printStackTrace();
} catch (IOException e) {
    // writing exception to log
    e.printStackTrace();
}

EntityUtils rất hữu ích.
Jay

6
Xin lỗi, nhưng bạn đã không bắt được bất kỳ lỗi nào, bạn đã giới thiệu chúng. Nắm bắt các ngoại lệ ở một nơi mà bạn không thể xử lý chúng là hoàn toàn sai và e.printStackTrace()không xử lý bất cứ điều gì.
maaartinus

java.net.ConnectException: Đã hết thời gian kết nối: kết nối
kerZy Hart


5

cách đơn giản nhất để gửi tham số với yêu cầu bài viết:

String postURL = "http://www.example.com/page.php";

HttpPost post = new HttpPost(postURL);

List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", "10"));

UrlEncodedFormEntity ent = new UrlEncodedFormEntity(params, "UTF-8");
post.setEntity(ent);

HttpClient client = new DefaultHttpClient();
HttpResponse responsePOST = client.execute(post);

Bạn đã làm. bây giờ bạn có thể sử dụng responsePOST. Nhận nội dung phản hồi dưới dạng chuỗi:

BufferedReader reader = new BufferedReader(new  InputStreamReader(responsePOST.getEntity().getContent()), 2048);

if (responsePOST != null) {
    StringBuilder sb = new StringBuilder();
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(" line : " + line);
        sb.append(line);
    }
    String getResponseString = "";
    getResponseString = sb.toString();
//use server output getResponseString as string value.
}

1

Gọi HttpURLConnection.setRequestMethod("POST")HttpURLConnection.setDoOutput(true);thực tế chỉ cần cái sau là POST sau đó trở thành phương thức mặc định.


đó là httpURLConnection.setRequestMethod () :)
Jose Diaz

1

Tôi khuyên bạn nên sử dụng http-request được xây dựng trên apache http api.

HttpRequest<String> httpRequest = HttpRequestBuilder.createPost("http://www.example.com/page.php", String.class)
.responseDeserializer(ResponseDeserializer.ignorableDeserializer()).build();

public void send(){
   String response = httpRequest.execute("id", "10").get();
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.