Java kullanarak nasıl çok parçalı / form veri POST isteğinde bulunabilirim?


97

Apache Commons HttpClient'in 3.x sürümünün günlerinde, çok parçalı / form veri POST isteğinde bulunmak mümkündü ( 2004'ten bir örnek ). Ne yazık ki bu, HttpClient 4.0 sürümünde artık mümkün değildir .

Temel faaliyetimiz olan "HTTP" için, çok bölümlü bir şekilde kapsam dışıdır. Kapsamında olduğu başka bir proje tarafından sürdürülen çok parçalı kodu kullanmayı çok isteriz, ancak ben hiçbirinin farkında değilim. Çok parçalı kodu birkaç yıl önce ortak kod çözücüye taşımaya çalıştık, ancak oradan çıkmadım. Oleg, kısa süre önce çok parçalı ayrıştırma koduna sahip başka bir projeden bahsetti ve çok parçalı biçimlendirme kodumuzla ilgilenebilir. Bunun şu anki durumunu bilmiyorum. ( http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html )

Çok parçalı / formlu veri POST isteğinde bulunabilen bir HTTP istemcisi yazmama izin veren herhangi bir Java kitaplığından haberdar olan var mı?

Arka plan: Zoho Writer'ın Remote API'sini kullanmak istiyorum .


Yanıtlar:


152

Çok parçalı dosya gönderimi yapmak için HttpClient 4.x kullanıyoruz.

GÜNCELLEME : HttpClient 4.3'ten itibaren bazı sınıflar kullanımdan kaldırılmıştır. İşte yeni API ile kod:

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şağıda, kullanımdan kaldırılmış HttpClient 4.0 API'sine sahip orijinal kod snippet'i verilmiştir :

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, çok parçalı şeyler org.apache.httpcomponents-httpmime-4.0'a taşındı! Bir yerde bahsedilebilir: /

Küçük dosyalarla sorunsuz çalışan, ancak büyük dosyalarla çalışmayan güncellenmiş kodunuzu denedim. Bu soruyla ilgili
AabinGunz

Merhaba ZZ, kodumda yukarıdaki değişikliği yaptım, ancak şu anda yeni bir sorunla karşı karşıyayım - REST uç noktam isteği kabul etmiyor. Aşağıdaki parametreleri bekliyor: ~ @ 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 ... Daha önce istek kabul ediliyordu. Ama şimdi 500 hatası alıyorum. Bunun neden olabileceğine dair bir fikriniz var mı?
Logan

Cevabı, kod örneğinin artık yatay kaydırılmaması için düzenledim --- kaydırma, kendi çalışmamda kullanmaya çalıştığımda önemli bir son parametreyi kaçırmama neden oldu.
G.Sylvie Davies

Güncellenen yanıt <dependency> <groupId> org.apache.httpcomponents </groupId> <artifactId> httpclient </artifactId> <version> 4.3.6 </version> </dependency> <! - için Maven bağımlılıkları aşağıda verilmiştir. mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -> <dependency> <groupId> org.apache.httpcomponents </groupId> <artifactId> httpmime </artifactId> <version> 4.3.6 </version> < / bağımlılık>
Wazime

39

Bunlar sahip olduğum Maven bağımlılıkları.

Java Kodu:

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

Pom.xml'deki Maven Bağımlılıkları:

<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
HttpEntitysınıf için en az 4.2'de httpcore'a da ihtiyacınız olacak
alalonde

19

JAR'ların boyutu önemliyse (örneğin, uygulama durumunda), HttpClient yerine java.net.HttpURLConnection ile httpmime doğrudan da kullanılabilir.

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

Kod:

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

Pom.xml'deki bağımlılık:

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

FileBody bu nereden geldi? Apace.http bileşenlerini kullanmamanın (kolay) bir yolu var mı?
Jr.

6

Çok parçalı postayı kullanarak sunucuya görüntüleri veya diğer dosyaları yüklemek için bu kodu kullanın.

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

}

aşağıdaki dosyaların yüklenmesini gerektirir.

kitaplıklar sınıf yolundadır httpclient-4.1.2.jar, httpcore-4.1.2.jar, httpmime-4.1.2.jar, httpclient-cache-4.1.2.jar, commons-codec.jarve commons-logging-1.1.1.jarolacaktır.


4

Ayrıca HTTP İstemcisi üzerinde oluşturulan REST Assured'ı da kullanabilirsiniz . Çok basit:

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

"Dosya" adlı bir kontrol adı alacaktır. Farklı bir kontrol adınız varsa, bunu belirtmeniz gerekir: multiPart("controlName", new File("/somedir/file.bin"))bkz. Github.com/rest-assured/rest-assured/wiki/…
asmaier

REST Assured harika bir API'ye sahiptir ve birçok özelliği destekler. Onunla çalışmak bir zevk. Ancak dürüst olmak gerekirse, bazı ısınma prosedürleri nedeniyle ilk aramada düşük performansla karşılaşabileceğinizi belirtmekte fayda var. İnternette daha fazla bilgi bulabilirsiniz, yani burada sqa.stackexchange.com/questions/39532/…
user1053510

REST Assured mükemmel bir kitaplıktır, ancak Web API testi için tasarlanmıştır ve üretim kodunda HTTP çağrıları yapmak için doğru araç olduğunu düşünmüyorum, elbette aynı temel kitaplıklardan yararlanıyor olsa bile.
Ranil Wijeyratne

3

İşte herhangi bir kitaplık gerektirmeyen bir çözüm.

Bu rutin dizindeki her dosyayı iletir d:/data/mpf10içinurlToConnect


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.1benim için çalıştı. Ancak, harici kavanozu apache-mime4j-0.6.jar ( org.apache.james.mime4j ) eklemek zorunda kaldım, aksi takdirde reqEntity.addPart("bin", bin);derleme olmazdı. Şimdi cazibe gibi çalışıyor.


2

Bu örneği Apache'nin Hızlı Başlangıç ​​Kılavuzunda buldum . 4.5 sürümü için:

/**
 * 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

Jdk dışında herhangi bir harici bağımlılık veya kitaplık kullanmadan çok parçalı form göndermenin saf bir java uygulamasına sahibiz. Https://github.com/atulsm/https-multipart-purejava/blob/master/src/main/java/com/atul/MultipartPure.java adresine bakın

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

Kodum multipartFile'ı sunucuya gönderiyor.

  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);
  }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.