Wie kann ich mit Java eine POST-Anfrage für mehrere Teile / Formulardaten stellen?

96

In den Tagen von Version 3.x von Apache Commons HttpClient war es möglich, eine POST-Anforderung für mehrere Teile / Formulardaten zu erstellen ( ein Beispiel aus dem Jahr 2004 ). Leider ist dies in Version 4.0 von HttpClient nicht mehr möglich .

Für unsere Kernaktivität "HTTP" ist Multipart etwas außerhalb des Geltungsbereichs. Wir würden gerne mehrteiligen Code verwenden, der von einem anderen Projekt verwaltet wird, für das er in den Geltungsbereich fällt, aber mir sind keine bekannt. Wir haben vor einigen Jahren versucht, den mehrteiligen Code in den Commons-Codec zu verschieben, aber ich bin dort nicht gestartet. Oleg hat kürzlich ein anderes Projekt erwähnt, das mehrteiligen Parsing-Code enthält und möglicherweise an unserem mehrteiligen Formatierungscode interessiert ist. Ich kenne den aktuellen Status dazu nicht. ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

Ist jemandem eine Java-Bibliothek bekannt, mit der ich einen HTTP-Client schreiben kann, der eine POST-Anforderung für mehrere Teile / Formulardaten stellen kann?

Hintergrund: Ich möchte die Remote-API von Zoho Writer verwenden .


quelle

Antworten:

151

Wir verwenden HttpClient 4.x, um mehrteilige Dateien zu veröffentlichen.

UPDATE : Ab HttpClient 4.3 sind einige Klassen veraltet. Hier ist der Code mit neuer 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();

Unten finden Sie den ursprünglichen Codeausschnitt mit der veralteten HttpClient 4.0-API :

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
quelle
62
Ah, das mehrteilige Zeug wurde nach org.apache.httpcomponents-httpmime-4.0 verschoben! Könnte irgendwo erwähnt werden: /
Ich habe Ihren aktualisierten Code ausprobiert, der mit kleinen Dateien gut funktioniert, aber mit großen Dateien nicht. Können Sie mir bei dieser Frage
AabinGunz
Hallo ZZ, ich habe die oben genannte Änderung in meinem Code vorgenommen, sehe mich jedoch jetzt einem neuen Problem gegenüber - mein REST-Endpunkt akzeptiert die Anforderung nicht. Es werden die folgenden Parameter erwartet: ~ @ PathVariable final String id, @RequestParam ("image") final MultipartFile image, @RequestParam ("l") final String l, @RequestParam ("lo") final String lo, @RequestParam (" bac ") final String bac, @RequestParam (" cac ") final String cac, @RequestParam (" m ") final String m ... Zuvor wurde die Anfrage akzeptiert. Aber jetzt bekomme ich 500 Fehler. Irgendwelche Ideen, warum dies passieren könnte?
Logan
Ich habe die Antwort so bearbeitet, dass das Codebeispiel nicht mehr horizontal scrollt. Durch das Scrollen habe ich einen wichtigen Endparameter übersehen, als ich versuchte, ihn in meiner eigenen Arbeit zu verwenden.
G. Sylvie Davies
Hier sind die Maven-Abhängigkeiten für die aktualisierte Antwort <dependency> <groupId> org.apache.httpcomponents </ groupId> <artifactId> httpclient </ifactId> <version> 4.3.6 </ version> </ dependency> <! - mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -> <dependency> <groupId> org.apache.httpcomponents </ groupId> <artifactId> httpmime </ arifactId> <version> 4.3.6 </ version> < / Abhängigkeit>
Wazime
39

Dies sind die Maven-Abhängigkeiten, die ich habe.

Java Code:

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

Maven-Abhängigkeiten 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>
Jaco van Niekerk
quelle
1
Sie benötigen auch httpcore, zumindest in 4.2, für die HttpEntityKlasse
Alalonde
18

Wenn die Größe der JARs von Bedeutung ist (z. B. im Falle eines Applets), kann httpmime auch direkt mit java.net.HttpURLConnection anstelle von HttpClient verwendet werden.

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

Code:

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

Abhängigkeit in pom.xml:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.2.4</version>
</dependency>
anre
quelle
FileBody woher kam das? Gibt es eine (einfache) Möglichkeit, apace.httpcomponents nicht zu verwenden?
Jr.
6

Verwenden Sie diesen Code, um Bilder oder andere Dateien mithilfe von mehrteiligen Beiträgen auf den Server hochzuladen.

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

}

Zum Hochladen sind die folgenden Dateien erforderlich.

Bibliotheken sind httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jarund commons-logging-1.1.1.jarsollen im Klassenpfad sein.

Java Man
quelle
4

Sie können auch REST Assured verwenden , das auf dem HTTP-Client aufbaut. Es ist sehr einfach:

given().multiPart(new File("/somedir/file.bin")).when().post("/fileUpload");
Johan
quelle
Es wird ein Kontrollname namens "Datei" angenommen. Wenn Sie einen anderen Kontrollnamen haben, müssen Sie diesen angeben: multiPart("controlName", new File("/somedir/file.bin"))siehe github.com/rest-assured/rest-assured/wiki/…
asmaier
REST Assured verfügt über eine hervorragende API und unterstützt viele Funktionen. Es ist eine Freude, damit zu arbeiten. Um fair zu sein, ist es erwähnenswert, dass aufgrund einiger Aufwärmvorgänge beim ersten Anruf möglicherweise eine Leistungsminderung auftritt. Weitere Informationen finden Sie im Internet, dh hier sqa.stackexchange.com/questions/39532/…
user1053510
REST Assured ist eine brillante Bibliothek, aber sie wurde für Web-API-Tests entwickelt und ich denke nicht, dass es das richtige Tool ist, um HTTP-Aufrufe im Produktionscode durchzuführen, obwohl natürlich dieselben zugrunde liegenden Bibliotheken verwendet werden.
Ranil Wijeyratne
3

Hier ist eine Lösung, für die keine Bibliotheken erforderlich sind.

Diese Routine überträgt jede Datei im Verzeichnis d:/data/mpf10anurlToConnect


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
user1005939
quelle
2

httpcomponents-client-4.0.1arbeitete für mich. Allerdings musste ich das externe JAR apache-mime4j-0.6.jar ( org.apache.james.mime4j ) hinzufügen, sonst reqEntity.addPart("bin", bin);würde es nicht kompiliert. Jetzt funktioniert es wie Charme.

Bob Yoplait
quelle
2

Ich habe dieses Beispiel in der Apache- Kurzanleitung gefunden . Es ist für Version 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();
        }
    }
}
Bernstein
quelle
0

Wir haben eine reine Java-Implementierung von Multipart-Form Submit ohne Verwendung externer Abhängigkeiten oder Bibliotheken außerhalb von JDK. Siehe 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
quelle
0

Mein Code post multipartFile to 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
quelle