¿Cómo puedo realizar una solicitud POST de datos de formulario o de varias partes utilizando Java?

96

En los días de la versión 3.x de Apache Commons HttpClient, era posible realizar una solicitud POST de múltiples partes / datos de formulario ( un ejemplo de 2004 ). Desafortunadamente, esto ya no es posible en la versión 4.0 de HttpClient .

Para nuestra actividad principal "HTTP", multiparte está algo fuera de alcance. Nos encantaría usar código de varias partes mantenido por algún otro proyecto para el que está dentro del alcance, pero no tengo conocimiento de ninguno. Intentamos mover el código multiparte a commons-codec hace unos años, pero no despegué allí. Oleg mencionó recientemente otro proyecto que tiene código de análisis de varias partes y podría estar interesado en nuestro código de formato de varias partes. No sé el estado actual de eso. ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

¿Alguien sabe de alguna biblioteca de Java que me permita escribir un cliente HTTP que pueda realizar una solicitud POST de datos de formulario / varias partes?

Antecedentes: quiero usar la API remota de Zoho Writer .


fuente

Respuestas:

151

Usamos HttpClient 4.x para publicar archivos de varias partes.

ACTUALIZACIÓN : A partir de HttpClient 4.3 , algunas clases han quedado obsoletas. Aquí está el código con la nueva 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();

A continuación, se muestra el fragmento de código original con la 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();
Codificador ZZ
fuente
62
¡Ah, el material de varias partes se ha movido a org.apache.httpcomponents-httpmime-4.0! Podría mencionarse en alguna parte: /
Probé su código actualizado que funciona bien con archivos pequeños pero no con archivos grandes. ¿Pueden ayudarme con esta pregunta?
AabinGunz
Hola ZZ, hice el cambio anterior en mi código, sin embargo, ahora estoy enfrentando un nuevo problema: mi punto final REST no acepta la solicitud. Se esperan los siguientes parámetros: ~ @ PathVariable ID de cadena final, @RequestParam ("imagen") imagen de MultipartFile final, @RequestParam ("l") Cadena final l, @RequestParam ("lo") cadena final lo, @RequestParam (" bac ") final String bac, @RequestParam (" cac ") final String cac, @RequestParam (" m ") final String m ... Anteriormente, se aceptaba la solicitud. Pero ahora recibo un error 500. Alguna idea de por qué esto esta pasando?
Logan
Edité la respuesta para que el ejemplo de código ya no se desplace horizontalmente: el desplazamiento me hizo perder un parámetro final importante cuando intenté usarlo en mi propio trabajo.
G. Sylvie Davies
Aquí están las dependencias de Maven para la respuesta actualizada <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> < / dependencia>
Wazime
39

Estas son las dependencias de Maven que tengo.

Código 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);

Dependencias de Maven en 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
fuente
1
también necesitará httpcore, al menos en 4.2, para la HttpEntityclase
alalonde
19

Si el tamaño de los archivos JAR es importante (por ejemplo, en el caso de un subprograma), también se puede usar http: // pmime con java.net.HttpURLConnection en lugar de 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

Código:

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

Dependencia en pom.xml:

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpmime</artifactId>
    <version>4.2.4</version>
</dependency>
anre
fuente
FileBody ¿de dónde vino esto? ¿Existe una manera (fácil) de no usar apace.httpcomponents?
Jr.
6

Utilice este código para cargar imágenes o cualquier otro archivo al servidor mediante publicación en varias partes.

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

}

requiere los siguientes archivos para cargar.

las bibliotecas están httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jary commons-logging-1.1.1.jarestarán en classpath.

Hombre de Java
fuente
4

También puede utilizar REST Assured, que se basa en HTTP Client. Es muy simple:

given().multiPart(new File("/somedir/file.bin")).when().post("/fileUpload");
Johan
fuente
Asumirá un nombre de control llamado "archivo". Si tiene un nombre de control diferente, debe especificarlo:, multiPart("controlName", new File("/somedir/file.bin"))consulte github.com/rest-assured/rest-assured/wiki/…
asmaier
REST Assured tiene una gran API y admite muchas funciones. Trabajar con él es un placer. Pero para ser justos, vale la pena mencionar que debido a algunos procedimientos de calentamiento, es posible que experimente una disminución del rendimiento en la primera llamada. Puede encontrar más información en Internet, es decir, aquí sqa.stackexchange.com/questions/39532/…
user1053510
REST Assured es una biblioteca brillante, pero está diseñada para pruebas de API web y no creo que sea la herramienta adecuada para realizar llamadas HTTP en código de producción, aunque, por supuesto, utiliza las mismas bibliotecas subyacentes.
Ranil Wijeyratne
3

Aquí hay una solución que no requiere bibliotecas.

Esta rutina transmite todos los archivos del directorio 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
usuario1005939
fuente
2

httpcomponents-client-4.0.1trabajó para mi. Sin embargo, tuve que agregar el jar externo apache-mime4j-0.6.jar ( org.apache.james.mime4j ); de lo contrario reqEntity.addPart("bin", bin);, no se compilaría. Ahora está funcionando a la perfección.

Bob Yoplait
fuente
2

Encontré esta muestra en la Guía de inicio rápido de Apache . Es para la versió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();
        }
    }
}
Ámbar
fuente
0

Tenemos una implementación java pura de envío de formularios multiparte sin usar dependencias externas o bibliotecas fuera de jdk. Consulte 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
fuente
0

Mi código publica multipartFile en el servidor.

  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
fuente