¿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 .


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

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>

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>

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.


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

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

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.


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

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

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);
  }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.