Làm cách nào để tạo yêu cầu POST nhiều phần / biểu mẫu-dữ liệu bằng Java?


96

Trong những ngày của phiên bản 3.x của Apache Commons HttpClient, việc thực hiện yêu cầu POST nhiều phần / biểu mẫu-dữ liệu đã có thể thực hiện được ( ví dụ từ năm 2004 ). Rất tiếc, điều này không còn khả thi trong phiên bản 4.0 của HttpClient .

Đối với hoạt động cốt lõi của chúng tôi "HTTP", đa phần có phần nằm ngoài phạm vi. Chúng tôi rất thích sử dụng mã nhiều phần được duy trì bởi một số dự án khác mà nó có trong phạm vi, nhưng tôi không biết về bất kỳ điều gì. Chúng tôi đã cố gắng chuyển mã nhiều phần sang commons-codec vài năm trước, nhưng tôi đã không thành công ở đó. Oleg gần đây đã đề cập đến một dự án khác có mã phân tích cú pháp nhiều phần và có thể quan tâm đến mã định dạng nhiều phần của chúng tôi. Tôi không biết tình trạng hiện tại về điều đó. ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

Có ai biết về bất kỳ thư viện Java nào cho phép tôi viết một ứng dụng khách HTTP có thể thực hiện yêu cầu POST nhiều phần / biểu mẫu-dữ liệu không?

Thông tin cơ bản: Tôi muốn sử dụng API từ xa của Zoho Writer .


Câu trả lời:


151

Chúng tôi sử dụng HttpClient 4.x để đăng tệp nhiều phần.

CẬP NHẬT : Kể từ HttpClient 4.3 , một số lớp không được dùng nữa. Đây là mã với API mới:

CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost uploadFile = new HttpPost("...");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.addTextBody("field1", "yes", ContentType.TEXT_PLAIN);

// This attaches the file to the POST:
File f = new File("[/path/to/upload]");
builder.addBinaryBody(
    "file",
    new FileInputStream(f),
    ContentType.APPLICATION_OCTET_STREAM,
    f.getName()
);

HttpEntity multipart = builder.build();
uploadFile.setEntity(multipart);
CloseableHttpResponse response = httpClient.execute(uploadFile);
HttpEntity responseEntity = response.getEntity();

Dưới đây là đoạn mã gốc với API HttpClient 4.0 không dùng nữa :

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);

FileBody bin = new FileBody(new File(fileName));
StringBody comment = new StringBody("Filename: " + fileName);

MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("bin", bin);
reqEntity.addPart("comment", comment);
httppost.setEntity(reqEntity);

HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();

62
Ah, nội dung nhiều phần đã được chuyển sang org.apache.httpcomponents-httpmime-4.0! Có thể được đề cập ở đâu đó: /

Tôi đã thử mã cập nhật của bạn hoạt động tốt với các tệp nhỏ nhưng không hoạt động với các tệp lớn. Bạn có thể giúp tôi với điều này câu hỏi
AabinGunz

Xin chào ZZ, tôi đã thực hiện thay đổi ở trên trong mã của mình, tuy nhiên, tôi đang gặp phải một vấn đề mới - điểm cuối REST của tôi không chấp nhận yêu cầu. Nó mong đợi các tham số sau: ~ @ PathVariable cuối cùng id chuỗi, @RequestParam ("hình ảnh") hình ảnh MultipartFile cuối cùng, @RequestParam ("l") Chuỗi cuối cùng l, @RequestParam ("lo") Chuỗi cuối cùng lo, @RequestParam (" bac ") final String bac, @RequestParam (" cac ") final String cac, @RequestParam (" m ") final String m ... Trước đây, yêu cầu đã được chấp nhận. Nhưng bây giờ tôi đang nhận được lỗi 500. Bất kỳ ý tưởng tại sao điều này có thể xảy ra?
Logan

Tôi đã chỉnh sửa câu trả lời để ví dụ mã không cuộn ngang nữa --- cuộn khiến tôi bỏ lỡ một tham số cuối cùng quan trọng khi tôi cố gắng sử dụng nó trong công việc của mình.
G. Sylvie Davies,

Đây là các phần phụ thuộc của Maven cho câu trả lời được cập nhật <dependency> <groupId> org.apache.httpcomponents </groupId> <artifactId> httpclient </artifactId> <version> 4.3.6 </version> </dependency> <! - mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -> <dependency> <groupId> org.apache.httpcomponents </groupId> <artifactId> httpmime </artifactId> <version> 4.3.6 </version> < / dependency>
Wazime

39

Đây là những phụ thuộc Maven mà tôi có.

Mã Java:

HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);

FileBody uploadFilePart = new FileBody(uploadFile);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("upload-file", uploadFilePart);
httpPost.setEntity(reqEntity);

HttpResponse response = httpclient.execute(httpPost);

Sự phụ thuộc của Maven trong pom.xml:

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.0.1</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpmime</artifactId>
  <version>4.0.1</version>
  <scope>compile</scope>
</dependency>

1
bạn sẽ cần httpcore là tốt, ít nhất là trong 4.2, cho HttpEntitylớp
alalonde

19

Nếu kích thước của các JAR quan trọng (ví dụ: trong trường hợp applet), người ta cũng có thể sử dụng trực tiếp httpmime với java.net.HttpURLConnection thay vì HttpClient.

httpclient-4.2.4:      423KB
httpmime-4.2.4:         26KB
httpcore-4.2.4:        222KB
commons-codec-1.6:     228KB
commons-logging-1.1.1:  60KB
Sum:                   959KB

httpmime-4.2.4:         26KB
httpcore-4.2.4:        222KB
Sum:                   248KB

Mã:

HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");

FileBody fileBody = new FileBody(new File(fileName));
MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.STRICT);
multipartEntity.addPart("file", fileBody);

connection.setRequestProperty("Content-Type", multipartEntity.getContentType().getValue());
OutputStream out = connection.getOutputStream();
try {
    multipartEntity.writeTo(out);
} finally {
    out.close();
}
int status = connection.getResponseCode();
...

Sự phụ thuộc vào pom.xml:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.2.4</version>
</dependency>

FileBody này đến từ đâu? Có cách nào (dễ dàng) để không sử dụng apace.httpcomponents không?
Jr.

6

Sử dụng mã này để tải hình ảnh hoặc bất kỳ tệp nào khác lên máy chủ bằng cách sử dụng đăng trong nhiều phần.

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;

public class SimplePostRequestTest {

    public static void main(String[] args) throws UnsupportedEncodingException, IOException {
        HttpClient httpclient = new DefaultHttpClient();
        HttpPost httppost = new HttpPost("http://192.168.0.102/uploadtest/upload_photo");

        try {
            FileBody bin = new FileBody(new File("/home/ubuntu/cd.png"));
            StringBody id = new StringBody("3");
            MultipartEntity reqEntity = new MultipartEntity();
            reqEntity.addPart("upload_image", bin);
            reqEntity.addPart("id", id);
            reqEntity.addPart("image_title", new StringBody("CoolPic"));

            httppost.setEntity(reqEntity);
            System.out.println("Requesting : " + httppost.getRequestLine());
            ResponseHandler<String> responseHandler = new BasicResponseHandler();
            String responseBody = httpclient.execute(httppost, responseHandler);
            System.out.println("responseBody : " + responseBody);

        } catch (ClientProtocolException e) {

        } finally {
            httpclient.getConnectionManager().shutdown();
        }
    }

}

nó yêu cầu các tệp bên dưới để tải lên.

các thư viện đã httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jarcommons-logging-1.1.1.jarđang ở trong classpath.


4

Bạn cũng có thể sử dụng REST Assured được xây dựng trên HTTP Client. Nó rất đơn giản:

given().multiPart(new File("/somedir/file.bin")).when().post("/fileUpload");

Nó sẽ giả sử một tên điều khiển được gọi là "tệp". Nếu bạn có tên điều khiển khác thì bạn cần chỉ định tên đó multiPart("controlName", new File("/somedir/file.bin"))
:,

REST Assured có API tuyệt vời và hỗ trợ nhiều tính năng. Làm việc với nó là một niềm vui. Nhưng công bằng mà nói, điều đáng nói là do một số quy trình khởi động, bạn có thể gặp phải tình trạng giảm hiệu suất trong cuộc gọi đầu tiên. Bạn có thể tìm thêm thông tin trên internet, tức là tại đây sqa.stackexchange.com/questions/39532/…
user1053510

REST Assured là một thư viện tuyệt vời, nhưng nó được thiết kế để kiểm tra API Web và tôi không nghĩ đó là công cụ phù hợp để thực hiện các lệnh gọi HTTP trong mã sản xuất, mặc dù tất nhiên nó sử dụng cùng các thư viện cơ bản.
Ranil Wijeyratne

3

Đây là một giải pháp không yêu cầu bất kỳ thư viện nào.

Quy trình này truyền mọi tệp trong thư d:/data/mpf10mục tớiurlToConnect


String boundary = Long.toHexString(System.currentTimeMillis());
URLConnection connection = new URL(urlToConnect).openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
PrintWriter writer = null;
try {
    writer = new PrintWriter(new OutputStreamWriter(connection.getOutputStream(), "UTF-8"));
    File dir = new File("d:/data/mpf10");
    for (File file : dir.listFiles()) {
        if (file.isDirectory()) {
            continue;
        }
        writer.println("--" + boundary);
        writer.println("Content-Disposition: form-data; name=\"" + file.getName() + "\"; filename=\"" + file.getName() + "\"");
        writer.println("Content-Type: text/plain; charset=UTF-8");
        writer.println();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
            for (String line; (line = reader.readLine()) != null;) {
                writer.println(line);
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
        }
    }
    writer.println("--" + boundary + "--");
} finally {
    if (writer != null) writer.close();
}
// Connection is lazily executed whenever you request any status.
int responseCode = ((HttpURLConnection) connection).getResponseCode();
// Handle response

2

httpcomponents-client-4.0.1đã làm cho tôi. Tuy nhiên, tôi phải thêm jar bên ngoài apache-mime4j-0.6.jar ( org.apache.james.mime4j ) nếu không reqEntity.addPart("bin", bin);sẽ không biên dịch được. Bây giờ nó hoạt động như một sự quyến rũ.


2

Tôi tìm thấy mẫu này trong Hướng dẫn bắt đầu nhanh của Apache . Nó dành cho phiên bản 4.5:

/**
 * Example how to use multipart/form encoded POST request.
 */
public class ClientMultipartFormPost {

    public static void main(String[] args) throws Exception {
        if (args.length != 1)  {
            System.out.println("File path not given");
            System.exit(1);
        }
        CloseableHttpClient httpclient = HttpClients.createDefault();
        try {
            HttpPost httppost = new HttpPost("http://localhost:8080" +
                    "/servlets-examples/servlet/RequestInfoExample");

            FileBody bin = new FileBody(new File(args[0]));
            StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);

            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addPart("bin", bin)
                    .addPart("comment", comment)
                    .build();


            httppost.setEntity(reqEntity);

            System.out.println("executing request " + httppost.getRequestLine());
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    System.out.println("Response content length: " + resEntity.getContentLength());
                }
                EntityUtils.consume(resEntity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }
}

0

Chúng tôi có một triển khai java thuần túy của gửi biểu mẫu nhiều phần mà không sử dụng bất kỳ thư viện hoặc phụ thuộc bên ngoài nào bên ngoài jdk. Tham khảo https://github.com/atulsm/https-multipart-purejava/blob/master/src/main/java/com/atul/MultipartPure.java

private static String body = "{\"key1\":\"val1\", \"key2\":\"val2\"}";
private static String subdata1 = "@@ -2,3 +2,4 @@\r\n";
private static String subdata2 = "<data>subdata2</data>";

public static void main(String[] args) throws Exception{        
    String url = "https://" + ip + ":" + port + "/dataupload";
    String token = "Basic "+ Base64.getEncoder().encodeToString((userName+":"+password).getBytes());

    MultipartBuilder multipart = new MultipartBuilder(url,token);       
    multipart.addFormField("entity", "main", "application/json",body);
    multipart.addFormField("attachment", "subdata1", "application/octet-stream",subdata1);
    multipart.addFormField("attachment", "subdata2", "application/octet-stream",subdata2);        
    List<String> response = multipart.finish();         
    for (String line : response) {
        System.out.println(line);
    }
}

0

Mã của tôi đăng MultiartFile lên máy chủ.

  public static HttpResponse doPost(
    String host,
    String path,
    String method,
    MultipartFile multipartFile
  ) throws IOException
  {

    HttpClient httpClient = wrapClient(host);
    HttpPost httpPost = new HttpPost(buildUrl(host, path));

    if (multipartFile != null) {

      HttpEntity httpEntity;

      ContentBody contentBody;
      contentBody = new ByteArrayBody(multipartFile.getBytes(), multipartFile.getOriginalFilename());
      httpEntity = MultipartEntityBuilder.create()
                                         .addPart("nameOfMultipartFile", contentBody)
                                         .build();

      httpPost.setEntity(httpEntity);

    }
    return httpClient.execute(httpPost);
  }
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.