Bagaimana cara membuat permintaan POST multipart / form-data menggunakan Java?

96

Pada masa Apache Commons HttpClient versi 3.x, membuat permintaan POST multipart / form-data dimungkinkan ( contoh dari 2004 ). Sayangnya ini tidak lagi memungkinkan dalam versi 4.0 dari HttpClient .

Untuk aktivitas inti kami "HTTP", multi bagian agak di luar cakupan. Kami ingin menggunakan kode multi bagian yang dikelola oleh beberapa proyek lain yang termasuk dalam cakupannya, tetapi saya tidak menyadarinya. Kami mencoba memindahkan kode multi bagian ke commons-codec beberapa tahun yang lalu, tetapi saya tidak melepasnya. Oleg baru-baru ini menyebutkan proyek lain yang memiliki kode parsing multi bagian dan mungkin tertarik dengan kode pemformatan multi bagian kami. Saya tidak tahu statusnya saat ini. ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

Adakah yang tahu tentang pustaka Java yang memungkinkan saya menulis klien HTTP yang dapat membuat permintaan POST multipart / form-data?

Latar belakang: Saya ingin menggunakan API Jarak Jauh Zoho Writer .


sumber

Jawaban:

152

Kami menggunakan HttpClient 4.x untuk membuat posting file multipart.

UPDATE : Pada HttpClient 4.3 , beberapa kelas sudah tidak digunakan lagi. Ini kode dengan API baru:

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

Di bawah ini adalah cuplikan asli kode dengan API HttpClient 4.0 yang tidak digunakan lagi :

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();
ZZ Coder
sumber
63
Ah, barang multibagian telah dipindahkan ke org.apache.httpcomponents-httpmime-4.0! Bisa disebutkan di suatu tempat: /
Saya mencoba kode Anda yang diperbarui yang berfungsi dengan baik dengan file kecil tetapi tidak berfungsi dengan file besar. Dapatkah Anda membantu saya dengan pertanyaan
AabinGunz
Hai ZZ, saya telah membuat perubahan di atas dalam kode saya, namun, saya menghadapi masalah baru sekarang - titik akhir REST saya tidak menerima permintaan tersebut. Ini mengharapkan parameter berikut: ~ @ PathVariable ID String akhir, @RequestParam ("image") gambar MultipartFile final, @RequestParam ("l") String akhir l, @RequestParam ("lo") String final lo, @RequestParam (" bac ") String final bac, @RequestParam (" cac ") string final cac, @RequestParam (" m ") string final m ... Sebelumnya, permintaan telah diterima. Tapi sekarang saya mendapatkan 500 kesalahan. Ada ide mengapa ini mungkin terjadi?
Logan
Saya mengedit jawabannya sehingga contoh kode tidak lagi menggulir horizontal --- gulungan itu menyebabkan saya kehilangan parameter akhir yang penting ketika saya mencoba menggunakannya dalam pekerjaan saya sendiri.
G. Sylvie Davies
Berikut adalah ketergantungan Maven untuk jawaban yang diperbarui <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> < / ketergantungan>
Wazime
39

Ini adalah dependensi Maven yang saya miliki.

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

Dependensi Maven di 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>
Jaco van Niekerk
sumber
1
Anda juga perlu httpcore, setidaknya di 4.2, untuk HttpEntitykelas
alalonde
19

Jika ukuran JAR penting (misalnya dalam kasus applet), seseorang juga dapat secara langsung menggunakan httpmime dengan java.net.HttpURLConnection daripada 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

Kode:

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

Ketergantungan di pom.xml:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.2.4</version>
</dependency>
anre
sumber
FileBody dari mana asalnya? Apakah ada cara (mudah) untuk tidak menggunakan apace.httpcomponents?
Jr.
6

Gunakan kode ini untuk mengunggah gambar atau file lainnya ke server menggunakan post in multipart.

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

}

itu membutuhkan file di bawah ini untuk mengunggah.

perpustakaan berada httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jardan commons-logging-1.1.1.jarberada di classpath.

Manusia Jawa
sumber
4

Anda juga dapat menggunakan REST Assured yang dibangun di atas Klien HTTP. Sangat sederhana:

given().multiPart(new File("/somedir/file.bin")).when().post("/fileUpload");
Johan
sumber
Ini akan mengasumsikan nama kontrol yang disebut "file". Jika Anda memiliki nama kontrol yang berbeda maka Anda perlu menentukannya :,multiPart("controlName", new File("/somedir/file.bin")) lihat github.com/rest-assured/rest-assured/wiki/…
asmaier
REST Assured memiliki API yang hebat dan mendukung banyak fitur. Bekerja dengannya adalah suatu kesenangan. Namun agar adil, perlu disebutkan bahwa karena beberapa prosedur pemanasan, Anda mungkin mengalami penurunan kinerja pada panggilan pertama. Anda dapat menemukan info lebih lanjut di internet yaitu di sini sqa.stackexchange.com/questions/39532/…
user1053510
REST Assured adalah pustaka yang brilian, tetapi dirancang untuk pengujian API Web dan menurut saya itu bukan alat yang tepat untuk membuat panggilan HTTP dalam kode produksi, meskipun tentu saja itu menggunakan pustaka dasar yang sama.
Ranil Wijeyratne
3

Berikut adalah solusi yang tidak memerlukan pustaka apa pun.

Rutin ini mengirimkan setiap file di direktori d:/data/mpf10keurlToConnect


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
pengguna1005939
sumber
2

httpcomponents-client-4.0.1bekerja untuk saya. Namun, saya harus menambahkan jar eksternal apache-mime4j-0.6.jar ( org.apache.james.mime4j ) jika reqEntity.addPart("bin", bin);tidak, tidak akan dapat dikompilasi. Sekarang bekerja seperti pesona.

Bob Yoplait
sumber
2

Saya menemukan contoh ini di Panduan Memulai Cepat Apache . Ini untuk versi 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();
        }
    }
}
Amber
sumber
0

Kami memiliki implementasi java murni dari pengiriman formulir multipart tanpa menggunakan dependensi eksternal atau library apa pun di luar jdk. Lihat 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);
    }
}
Atul Soman
sumber
0

Kode saya memposting multipartFile ke server.

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