Come posso effettuare una richiesta POST multipart / form-data utilizzando Java?


96

Ai tempi della versione 3.x di Apache Commons HttpClient, era possibile effettuare una richiesta POST multipart / form-data ( un esempio del 2004 ). Purtroppo questo non è più possibile nella versione 4.0 di HttpClient .

Per la nostra attività principale "HTTP", multipart è alquanto fuori portata. Ci piacerebbe utilizzare codice multiparte gestito da qualche altro progetto per il quale è nell'ambito, ma non ne sono a conoscenza. Abbiamo provato a spostare il codice multiparte su commons-codec alcuni anni fa, ma non sono decollato lì. Oleg ha recentemente menzionato un altro progetto che ha un codice di analisi multiparte e potrebbe essere interessato al nostro codice di formattazione multipart. Non conosco lo stato attuale di questo. ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

Qualcuno è a conoscenza di una libreria Java che mi consente di scrivere un client HTTP che può effettuare una richiesta POST multipart / form-data?

Sfondo: voglio utilizzare l' API remota di Zoho Writer .


Risposte:


152

Usiamo HttpClient 4.x per creare file multipart post.

AGGIORNAMENTO : A partire da HttpClient 4.3 , alcune classi sono state deprecate. Ecco il codice con la nuova API:

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 seguito è riportato lo snippet di codice originale con l' API HttpClient 4.0 obsoleta :

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

63
Ah, il materiale multiparte è stato spostato in org.apache.httpcomponents -”pmime-4.0! Potrebbe essere menzionato da qualche parte: /

Ho provato il tuo codice aggiornato che funziona bene con file piccoli ma non funziona con file di grandi dimensioni. Potete aiutarmi con questa domanda
AabinGunz

Ciao ZZ, ho apportato la modifica di cui sopra nel mio codice, tuttavia, sto affrontando un nuovo problema ora: il mio endpoint REST non accetta la richiesta. Prevede i seguenti parametri: ~ @ PathVariable final String id, @RequestParam ("image") final MultipartFile image, @RequestParam ("l") final String l, @RequestParam ("lo") final String lo, @RequestParam (" bac ") stringa finale bac, @RequestParam (" cac ") stringa finale cac, @RequestParam (" m ") stringa finale m ... In precedenza, la richiesta veniva accettata. Ma ora ricevo l'errore 500. Qualche idea sul perché potrebbe accadere?
Logan

Ho modificato la risposta in modo che l'esempio di codice non scorra più in orizzontale: lo scorrimento mi ha fatto perdere un importante parametro finale quando ho provato a usarlo nel mio lavoro.
G. Sylvie Davies

Ecco le dipendenze Maven per la risposta aggiornata <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>”pmime </artifactId> <version> 4.3.6 </version> < / dipendenza>
Wazime

39

Queste sono le dipendenze di Maven che ho.

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

Dipendenze di Maven in 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
avrai bisogno anche di httpcore, almeno in 4.2, per la HttpEntityclasse
alalonde

19

Se la dimensione dei JAR è importante (ad esempio in caso di applet), è anche possibile utilizzare direttamente http://tpmime con java.net.HttpURLConnection invece di 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

Codice:

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

Dipendenza in pom.xml:

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

FileBody da dove viene questo? Esiste un modo (semplice) per non utilizzare apace.httpcomponents?
Jr.

6

Usa questo codice per caricare immagini o altri file sul server utilizzando 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();
        }
    }

}

richiede di seguito i file da caricare.

le librerie sono httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jare commons-logging-1.1.1.jardevono essere in classpath.


4

È inoltre possibile utilizzare REST Assured che si basa sul client HTTP. È molto semplice:

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

Assumerà un nome di controllo chiamato "file". Se hai un nome di controllo diverso, devi specificarlo multiPart("controlName", new File("/somedir/file.bin"))
:,

REST Assured ha un'ottima API e supporta molte funzionalità. Lavorarci è un piacere. Ma per essere onesti, vale la pena ricordare che a causa di alcune procedure di riscaldamento potresti riscontrare una riduzione delle prestazioni alla prima chiamata. Puoi trovare maggiori informazioni su Internet, ad esempio qui sqa.stackexchange.com/questions/39532/…
user1053510

REST Assured è una libreria brillante, ma è progettata per il test delle API Web e non penso che sia lo strumento giusto per effettuare chiamate HTTP nel codice di produzione, anche se ovviamente utilizza le stesse librerie sottostanti.
Ranil Wijeyratne

3

Ecco una soluzione che non richiede alcuna libreria.

Questa routine trasmette ogni file nella directory d:/data/mpf10aurlToConnect


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.1ha funzionato per me. Tuttavia, ho dovuto aggiungere il jar esterno apache-mime4j-0.6.jar ( org.apache.james.mime4j ) altrimenti reqEntity.addPart("bin", bin);non si sarebbe compilato. Ora funziona come un fascino.


2

Ho trovato questo esempio nella Guida rapida di Apache . È per la versione 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

Abbiamo un'implementazione java pura dell'invio di moduli multipart senza l'utilizzo di dipendenze o librerie esterne al di fuori di jdk. Fare riferimento a 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

Il mio codice invia multipartFile al 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);
  }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.