在Apache Commons HttpClient的3.x版本中,可以进行多部分/表单数据POST请求(2004年的示例)。不幸的是,在HttpClient的4.0版中这不再可能。


对于我们的核心活动“ HTTP”,multipart在某种程度上超出了范围。我们很乐意使用由
其他项目维护的多部分代码,但我对此一无所知。
几年前,我们曾尝试将多部分代码移至commons编解码器,但我没有在那儿起飞。 Oleg最近提到了另一个
项目,该项目具有多部分解析代码,并且可能对我们的多部分格式代码感兴趣。我不知道它的当前状态。 (http://www.nabble.com/multipart-form-data-in-4.0-td14224819.html)


有人知道任何允许我编写一个Java库的Java库吗?可以发出多部分/表单数据POST请求的HTTP客户端?

背景:我想使用Zoho Writer的Remote API。

评论

另请参阅-bayou.io/release/1.0/docs/http/Http_Client.html

#1 楼

我们使用HttpClient 4.x进行多部分文件发布。

更新:从HttpClient 4.3开始,不赞成使用某些类。以下是使用新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();


下面是不推荐使用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();


评论


嗯,多部分内容已移至org.apache.httpcomponents-httpmime-4.0!可以在某处提到:/

–lutz
09年9月4日13:00

我尝试了更新的代码,该代码适用于小文件,但不适用于大文件。你能帮我解决这个问题吗

– AabinGunz
2014-09-19 5:25



嗨,ZZ,我已经在代码中进行了上述更改,但是,我现在面临一个新问题-我的REST端点不接受请求。期望使用以下参数:〜@ PathVariable最终字符串id,@ RequestParam(“ image”)最终MultipartFile图像,@ RequestParam(“ l”)最终字符串l,@ RequestParam(“ lo”)最终字符串lo,@ RequestParam(“ bac“)最终字符串bac,@ RequestParam(” cac“)最终字符串cac,@ RequestParam(” m“)最终字符串m ...以前,该请求已被接受。但是现在我收到500错误。任何想法为什么会发生这种情况?

–登录
15年7月27日在10:59



我编辑了答案,以便代码示例不再进行水平滚动---当我尝试在自己的工作中使用滚动时,滚动导致我错过了重要的最终参数。

– G.西尔维·戴维斯
16年7月14日在19:56



这是更新答案 org.apache.httpcomponents httpclient 4.3.6 <!- mvnrepository.com/artifact/org.apache.httpcomponents/httpmime-> org.apache.httpcomponents httpmime 4.3.6 < /依赖性>

– Wazime
17年3月3日在16:47

#2 楼

这些是我具有的Maven依赖项。

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


pom.xml中的Maven依赖项:

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


评论


至少在4.2中,您还将需要HttpEntity类的httpcore

– alalonde
2012年7月3日,下午3:58

#3 楼

如果JAR的大小很重要(例如,在applet的情况下),则还可以直接将java.net.HttpURLConnection使用httpmime而不是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


代码:

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中的依赖项:

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


评论


FileBody来自哪里?有没有不使用apache.httpcomponents的(简便)方法?

–小
16年5月5日在19:13

#4 楼

使用此代码可以通过多部分发布将图像或任何其他文件上传到服务器。

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

}


它需要以下文件上传。

库是
httpclient-4.1.2.jar,
httpcore-4.1.2.jar,
httpmime-4.1.2.jar,
httpclient-cache-4.1.2.jar,
commons-codec.jar
commons-logging-1.1.1.jar属于类路径。

#5 楼

您还可以使用基于HTTP客户端构建的REST保证。非常简单:

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


评论


它将假定控件名称为“文件”。如果您有其他控件名称,则需要指定它:multiPart(“ controlName”,new File(“ / somedir / file.bin”)),请参阅github.com/rest-assured/rest-assured/wiki/…

– asmaier
17年12月8日在10:23

REST Assured具有出色的API,并支持许多功能。使用它是一种乐趣。但公平地说,值得一提的是,由于某些预热程序,您在首次通话时可能会遇到性能下降的情况。您可以在互联网上找到更多信息,即在此处sqa.stackexchange.com/questions/39532/…

–user1053510
2月19日7:42

REST Assured是一个出色的库,但是它是为Web API测试而设计的,我认为它不是在生产代码中进行HTTP调用的正确工具,尽管它当然使用了相同的基础库。

–Ranil Wijeyratne
5月19日6:59

#6 楼

这是不需要任何库的解决方案。

此例程将目录d:/data/mpf10中的每个文件传输到urlToConnect


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


#7 楼

httpcomponents-client-4.0.1为我工作。但是,我必须添加外部jar apache-mime4j-0.6.jar(org.apache.james.mime4j),否则
reqEntity.addPart("bin", bin);无法编译。现在它就像魅力一样工作。

#8 楼

我在Apache的《快速入门指南》中找到了此示例。适用于版本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();
        }
    }
}


#9 楼

我们有纯Java的multipart-form提交实现,无需使用jdk之外的任何外部依赖项或库。请参阅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);
    }
}


#10 楼

我的代码将multipartFile发布到服务器。

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


#11 楼

我的代码用于使用多部分的post将文件发送到服务器。
在请求发送表单数据时充分利用多值映射
  LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("FILE", new FileSystemResource(file));
        map.add("APPLICATION_ID", Number);

   httpService.post( map,headers);


在接收方最终使用
@RequestMapping(value = "fileUpload", method = RequestMethod.POST)
    public ApiResponse AreaCsv(@RequestParam("FILE") MultipartFile file,@RequestHeader("clientId") ){
//code
}